Compare commits

...

9 Commits

9 changed files with 207 additions and 109 deletions

View File

@@ -1147,7 +1147,7 @@ static void CL_CheckForResend( void )
if(( host.realtime - cls.connect_time ) < resendTime )
return;
res = NET_StringToAdrNB( cls.servername, &adr );
res = NET_StringToAdrNB( cls.servername, &adr, false );
if( res == NET_EAI_NONAME )
{

View File

@@ -272,6 +272,15 @@ static qboolean Cvar_ValidateVarName( const char *s, qboolean isvalue )
return true;
}
static void Cvar_Free( convar_t *var )
{
freestring( var->name );
freestring( var->string );
freestring( var->def_string );
freestring( var->desc );
Mem_Free( var );
}
/*
============
Cvar_UnlinkVar
@@ -311,17 +320,13 @@ static int Cvar_UnlinkVar( const char *var_name, int group )
#endif
// unlink variable from list
freestring( var->string );
*prev = var->next;
// only allocated cvars can throw these fields
if( FBitSet( var->flags, FCVAR_ALLOCATED ))
{
freestring( var->name );
freestring( var->def_string );
freestring( var->desc );
Mem_Free( var );
}
Cvar_Free( var );
else
freestring( var->string );
count++;
}
@@ -1217,6 +1222,20 @@ static void Cvar_List_f( void )
Con_Printf( "\n%i cvars\n", count );
}
static qboolean Cvar_ValidateUnlinkGroup( int group )
{
if( FBitSet( group, FCVAR_EXTDLL ) && !Cvar_VariableInteger( "host_gameloaded" ))
return false;
if( FBitSet( group, FCVAR_CLIENTDLL ) && !Cvar_VariableInteger( "host_clientloaded" ))
return false;
if( FBitSet( group, FCVAR_GAMEUIDLL ) && !Cvar_VariableInteger( "host_gameuiloaded" ))
return false;
return true;
}
/*
============
Cvar_Unlink
@@ -1228,19 +1247,88 @@ void Cvar_Unlink( int group )
{
int count;
if( Cvar_VariableInteger( "host_gameloaded" ) && FBitSet( group, FCVAR_EXTDLL ))
return;
if( Cvar_VariableInteger( "host_clientloaded" ) && FBitSet( group, FCVAR_CLIENTDLL ))
return;
if( Cvar_VariableInteger( "host_gameuiloaded" ) && FBitSet( group, FCVAR_GAMEUIDLL ))
if( !Cvar_ValidateUnlinkGroup( group ))
return;
count = Cvar_UnlinkVar( NULL, group );
Con_Reportf( "unlink %i cvars\n", count );
}
pending_cvar_t *Cvar_PrepareToUnlink( int group )
{
pending_cvar_t *list = NULL;
convar_t *cv;
for( cv = cvar_vars; cv != NULL; cv = cv->next )
{
size_t namelen;
pending_cvar_t *p;
if( !FBitSet( cv->flags, group ))
continue;
namelen = Q_strlen( cv->name ) + 1;
p = Mem_Malloc( host.mempool, sizeof( *list ) + namelen );
p->next = list;
p->cv_cur = cv;
p->cv_next = cv->next;
p->cv_allocated = FBitSet( cv->flags, FCVAR_ALLOCATED ) ? true : false;
Q_strncpy( p->cv_name, cv->name, namelen );
list = p;
}
return list;
}
void Cvar_UnlinkPendingCvars( pending_cvar_t *list )
{
int count = 0;
while( list != NULL )
{
pending_cvar_t *next = list->next;
convar_t *cv_prev, *cv;
for( cv_prev = NULL, cv = cvar_vars; cv != NULL; cv_prev = cv, cv = cv->next )
{
if( cv == list->cv_cur )
break;
}
if( cv == NULL )
{
Con_Reportf( "%s: can't find %s in variable list\n", __func__, list->cv_name );
Mem_Free( list );
list = next;
continue;
}
// unlink cvar from list
BaseCmd_Remove( HM_CVAR, list->cv_name );
if( cv_prev != NULL )
cv_prev->next = list->cv_next;
else cvar_vars = list->cv_next;
if( list->cv_allocated )
Cvar_Free( list->cv_cur );
else
{
// TODO: can't free cvar string here because
// it's not safe to access cv_cur and
// can't save string pointer because it could've been changed
// and pointer to it is already lost
// freestring( list->cv_string );
}
// now free pending cvar
Mem_Free( list );
list = next;
count++;
}
Con_Reportf( "unlink %i cvars\n", count );
}
/*
============
Cvar_Init

View File

@@ -18,6 +18,18 @@ GNU General Public License for more details.
#include "cvardef.h"
// As some mods dynamically allocate cvars and free them without notifying the engine
// let's construct a list of cvars that must be removed
typedef struct pending_cvar_s
{
struct pending_cvar_s *next;
convar_t *cv_cur; // preserve the data that might get freed
convar_t *cv_next;
qboolean cv_allocated; // if it's allocated by us, it's safe to access cv_cur
char cv_name[];
} pending_cvar_t;
cvar_t *Cvar_GetList( void );
#define Cvar_FindVar( name ) Cvar_FindVarExt( name, 0 )
convar_t *Cvar_FindVarExt( const char *var_name, int ignore_group );
@@ -43,4 +55,7 @@ void Cvar_Init( void );
void Cvar_PostFSInit( void );
void Cvar_Unlink( int group );
pending_cvar_t *Cvar_PrepareToUnlink( int group );
void Cvar_UnlinkPendingCvars( pending_cvar_t *pending_cvars );
#endif//CVAR_H

View File

@@ -21,6 +21,7 @@ typedef struct master_s
struct master_s *next;
qboolean sent; // TODO: get rid of this internal state
qboolean save;
qboolean v6only;
string address;
netadr_t adr; // temporary, rewritten after each send
@@ -45,7 +46,7 @@ NET_GetMasterHostByName
*/
static net_gai_state_t NET_GetMasterHostByName( master_t *m )
{
net_gai_state_t res = NET_StringToAdrNB( m->address, &m->adr );
net_gai_state_t res = NET_StringToAdrNB( m->address, &m->adr, m->v6only );
if( res == NET_EAI_OK )
return res;
@@ -251,7 +252,7 @@ NET_AddMaster
Add master to the list
========================
*/
static void NET_AddMaster( const char *addr, qboolean save )
static void NET_AddMaster( const char *addr, qboolean save, qboolean v6only )
{
master_t *master, *last;
@@ -261,10 +262,11 @@ static void NET_AddMaster( const char *addr, qboolean save )
return;
}
master = Mem_Malloc( host.mempool, sizeof( master_t ) );
master = Mem_Malloc( host.mempool, sizeof( *master ) );
Q_strncpy( master->address, addr, sizeof( master->address ));
master->sent = false;
master->save = save;
master->v6only = v6only;
master->next = NULL;
master->adr.type = 0;
@@ -283,7 +285,7 @@ static void NET_AddMaster_f( void )
return;
}
NET_AddMaster( Cmd_Argv( 1 ), true ); // save them into config
NET_AddMaster( Cmd_Argv( 1 ), true, false ); // save them into config
ml.modified = true; // save config
}
@@ -316,15 +318,14 @@ static void NET_ListMasters_f( void )
master_t *list;
int i;
Msg( "Master servers\n=============\n" );
Con_Printf( "Master servers:\n" );
for( i = 1, list = ml.list; list; i++, list = list->next )
{
Msg( "%d\t%s", i, list->address );
Con_Printf( "%d\t%s", i, list->address );
if( list->adr.type != 0 )
Msg( "\t%s\n", NET_AdrToString( list->adr ));
else Msg( "\n" );
Con_Printf( "\t%s\n", NET_AdrToString( list->adr ));
else Con_Printf( "\n" );
}
}
@@ -354,11 +355,15 @@ static void NET_LoadMasters( void )
// format: master <addr>\n
while( ( pfile = COM_ParseFile( pfile, token, sizeof( token ) ) ) )
{
if( !Q_strcmp( token, "master" ) ) // load addr
if( !Q_strcmp( token, "master" )) // load addr
{
pfile = COM_ParseFile( pfile, token, sizeof( token ) );
NET_AddMaster( token, true );
NET_AddMaster( token, true, false );
}
else if( !Q_strcmp( token, "master6" ))
{
pfile = COM_ParseFile( pfile, token, sizeof( token ) );
NET_AddMaster( token, true, true );
}
}
@@ -396,7 +401,7 @@ void NET_SaveMasters( void )
for( m = ml.list; m; m = m->next )
{
if( m->save )
FS_Printf( f, "master %s\n", m->address );
FS_Printf( f, "%s %s\n", m->v6only ? "master6" : "master", m->address );
}
FS_Close( f );
@@ -418,10 +423,10 @@ void NET_InitMasters( void )
Cvar_RegisterVariable( &sv_verbose_heartbeats );
// keep main master always there
NET_AddMaster( MASTERSERVER_ADR, false );
NET_AddMaster( "aaaa.mentality.rip:27010", false ); // IPv6-only
NET_AddMaster( "mentality.rip:27011", false ); // testing server, might be offline
NET_AddMaster( "aaaa.mentality.rip:27011", false ); // IPv6-only, testing server, might be offline
NET_AddMaster( MASTERSERVER_ADR, false, false );
NET_AddMaster( "aaaa.mentality.rip:27010", false, true ); // IPv6-only
NET_AddMaster( "mentality.rip:27011", false, false ); // testing server, might be offline
NET_AddMaster( "aaaa.mentality.rip:27011", false, true ); // IPv6-only, testing server, might be offline
NET_LoadMasters( );
}

View File

@@ -18,16 +18,16 @@ GNU General Public License for more details.
#include "netchan.h"
#include "xash3d_mathlib.h"
#include "ipv6text.h"
#if XASH_WIN32
#include "platform/win32/net.h"
#elif defined XASH_NO_NETWORK
#if XASH_NO_NETWORK
#include "platform/stub/net_stub.h"
#else
#include "platform/posix/net.h"
#endif
#if XASH_PSVITA
#elif XASH_WIN32
#include "platform/win32/net.h"
#elif XASH_PSVITA
#include "platform/psvita/net_psvita.h"
static const struct in6_addr in6addr_any;
#else
#include "platform/posix/net.h"
#endif
#if XASH_SDL == 2
@@ -119,6 +119,7 @@ static CVAR_DEFINE( net_ipclientport, "ip_clientport", "0", FCVAR_READ_ONLY, "ne
static CVAR_DEFINE( net_clientport, "clientport", "0", FCVAR_READ_ONLY, "network default client port" );
static CVAR_DEFINE( net_fakelag, "fakelag", "0", FCVAR_PRIVILEGED, "lag all incoming network data (including loopback) by xxx ms." );
static CVAR_DEFINE( net_fakeloss, "fakeloss", "0", FCVAR_PRIVILEGED, "act like we dropped the packet this % of the time." );
static CVAR_DEFINE_AUTO( net_resolve_debug, "0", FCVAR_PRIVILEGED, "print resolve thread debug messages" );
CVAR_DEFINE( net_clockwindow, "clockwindow", "0.5", FCVAR_PRIVILEGED, "timewindow to execute client moves" );
netadr_t net_local;
@@ -130,6 +131,8 @@ static CVAR_DEFINE( net_ip6hostport, "ip6_hostport", "0", FCVAR_READ_ONLY, "netw
static CVAR_DEFINE( net_ip6clientport, "ip6_clientport", "0", FCVAR_READ_ONLY, "network ip6 client port" );
static CVAR_DEFINE_AUTO( net6_address, "0", FCVAR_PRIVILEGED|FCVAR_READ_ONLY, "contain local IPv6 address of current client" );
static void NET_ClearLagData( qboolean bClient, qboolean bServer );
/*
====================
NET_ErrorString
@@ -196,7 +199,7 @@ static char *NET_ErrorString( void )
#endif
}
_inline socklen_t NET_SockAddrLen( const struct sockaddr_storage *addr )
static inline socklen_t NET_SockAddrLen( const struct sockaddr_storage *addr )
{
switch ( addr->ss_family )
{
@@ -209,7 +212,7 @@ _inline socklen_t NET_SockAddrLen( const struct sockaddr_storage *addr )
}
}
_inline qboolean NET_IsSocketError( int retval )
static inline qboolean NET_IsSocketError( int retval )
{
#if XASH_WIN32 || XASH_DOS4GW
return retval == SOCKET_ERROR ? true : false;
@@ -218,7 +221,7 @@ _inline qboolean NET_IsSocketError( int retval )
#endif
}
_inline qboolean NET_IsSocketValid( int socket )
static inline qboolean NET_IsSocketValid( int socket )
{
#if XASH_WIN32 || XASH_DOS4GW
return socket != INVALID_SOCKET;
@@ -253,40 +256,27 @@ static void NET_NetadrToSockadr( netadr_t *a, struct sockaddr_storage *s )
if( a->type == NA_BROADCAST )
{
((struct sockaddr_in *)s)->sin_family = AF_INET;
s->ss_family = AF_INET;
((struct sockaddr_in *)s)->sin_port = a->port;
((struct sockaddr_in *)s)->sin_addr.s_addr = INADDR_BROADCAST;
}
else if( a->type == NA_IP )
{
((struct sockaddr_in *)s)->sin_family = AF_INET;
s->ss_family = AF_INET;
((struct sockaddr_in *)s)->sin_port = a->port;
((struct sockaddr_in *)s)->sin_addr.s_addr = a->ip4;
}
else if( a->type6 == NA_IP6 )
{
struct in6_addr ip6;
NET_NetadrToIP6Bytes( ip6.s6_addr, a );
if( IN6_IS_ADDR_V4MAPPED( &ip6 ))
{
((struct sockaddr_in *)s)->sin_family = AF_INET;
((struct sockaddr_in *)s)->sin_addr.s_addr = *(uint32_t *)(ip6.s6_addr + 12);
((struct sockaddr_in *)s)->sin_port = a->port;
}
else
{
((struct sockaddr_in6 *)s)->sin6_family = AF_INET6;
memcpy( &((struct sockaddr_in6 *)s)->sin6_addr, &ip6, sizeof( struct in6_addr ));
((struct sockaddr_in6 *)s)->sin6_port = a->port;
}
s->ss_family = AF_INET6;
((struct sockaddr_in6 *)s)->sin6_port = a->port;
NET_NetadrToIP6Bytes(((struct sockaddr_in6 *)s)->sin6_addr.s6_addr, a );
}
else if( a->type6 == NA_MULTICAST_IP6 )
{
((struct sockaddr_in6 *)s)->sin6_family = AF_INET6;
memcpy(((struct sockaddr_in6 *)s)->sin6_addr.s6_addr, k_ipv6Bytes_LinkLocalAllNodes, sizeof( struct in6_addr ));
s->ss_family = AF_INET6;
((struct sockaddr_in6 *)s)->sin6_port = a->port;
memcpy(((struct sockaddr_in6 *)s)->sin6_addr.s6_addr, k_ipv6Bytes_LinkLocalAllNodes, sizeof( struct in6_addr ));
}
}
@@ -305,13 +295,8 @@ static void NET_SockadrToNetadr( const struct sockaddr_storage *s, netadr_t *a )
}
else if( s->ss_family == AF_INET6 )
{
a->type6 = NA_IP6;
NET_IP6BytesToNetadr( a, ((struct sockaddr_in6 *)s)->sin6_addr.s6_addr );
if( IN6_IS_ADDR_V4MAPPED( &((struct sockaddr_in6 *)s)->sin6_addr ))
a->type = NA_IP;
else
a->type6 = NA_IP6;
a->port = ((struct sockaddr_in6 *)s)->sin6_port;
}
}
@@ -328,6 +313,11 @@ static qboolean NET_GetHostByName( const char *hostname, int family, struct sock
struct addrinfo hints;
qboolean ret = false;
#if XASH_NO_IPV6_RESOLVE
if( family == AF_INET6 )
return false;
#endif
memset( &hints, 0, sizeof( hints ));
hints.ai_family = family;
@@ -350,6 +340,12 @@ static qboolean NET_GetHostByName( const char *hostname, int family, struct sock
return ret;
#else
struct hostent *h;
#if XASH_NO_IPV6_RESOLVE
if( family == AF_INET6 )
return false;
#endif
if(!( h = gethostbyname( hostname )))
return false;
@@ -413,11 +409,7 @@ DWORD WINAPI NET_ThreadStart( LPVOID unused )
}
#endif // !_WIN32
#ifdef DEBUG_RESOLVE
#define RESOLVE_DBG(x) Sys_PrintLog(x)
#else
#define RESOLVE_DBG(x)
#endif // DEBUG_RESOLVE
#define RESOLVE_DBG( x ) do { if( net_resolve_debug.value ) Sys_PrintLog(( x )); } while( 0 )
static struct nsthread_s
{
@@ -441,13 +433,18 @@ static void NET_InitializeCriticalSections( void )
static void NET_DeleteCriticalSections( void )
{
net.threads_initialized = false;
if( net.threads_initialized )
{
mutex_destroy( nsthread.mutexns );
mutex_destroy( nsthread.mutexres );
mutex_destroy( nsthread.mutexns );
mutex_destroy( nsthread.mutexres );
net.threads_initialized = false;
}
memset( &nsthread, 0, sizeof( nsthread ));
}
void NET_ResolveThread( void )
static void NET_ResolveThread( void )
{
struct sockaddr_storage addr;
qboolean res;
@@ -566,11 +563,9 @@ static net_gai_state_t NET_StringToSockaddr( const char *s, struct sockaddr_stor
asyncfailed = false;
return NET_EAI_AGAIN;
}
else // failed to create thread
{
Con_Reportf( S_ERROR "%s: failed to create thread!\n", __func__ );
nsthread.busy = false;
}
Con_Reportf( S_ERROR "%s: failed to create thread!\n", __func__ );
nsthread.busy = false;
}
mutex_unlock( nsthread.mutexres );
@@ -578,9 +573,7 @@ static net_gai_state_t NET_StringToSockaddr( const char *s, struct sockaddr_stor
#endif // CAN_ASYNC_NS_RESOLVE
if( asyncfailed )
{
ret = NET_GetHostByName( copy, family, &temp );
}
if( !ret )
{
@@ -594,16 +587,9 @@ static net_gai_state_t NET_StringToSockaddr( const char *s, struct sockaddr_stor
sadr->ss_family = temp.ss_family;
if( temp.ss_family == AF_INET )
{
((struct sockaddr_in *)sadr)->sin_addr =
((struct sockaddr_in*)&temp)->sin_addr;
}
((struct sockaddr_in *)sadr)->sin_addr = ((struct sockaddr_in*)&temp)->sin_addr;
else if( temp.ss_family == AF_INET6 )
{
memcpy(&((struct sockaddr_in6 *)sadr)->sin6_addr,
&((struct sockaddr_in6*)&temp)->sin6_addr,
sizeof( struct in6_addr ));
}
((struct sockaddr_in6 *)sadr)->sin6_addr = ((struct sockaddr_in6*)&temp)->sin6_addr;
}
return NET_EAI_OK;
@@ -1066,19 +1052,20 @@ qboolean NET_StringToAdr( const char *string, netadr_t *adr )
return NET_StringToAdrEx( string, adr, AF_UNSPEC );
}
net_gai_state_t NET_StringToAdrNB( const char *string, netadr_t *adr )
net_gai_state_t NET_StringToAdrNB( const char *string, netadr_t *adr, qboolean v6only )
{
struct sockaddr_storage s;
net_gai_state_t res;
memset( adr, 0, sizeof( netadr_t ));
if( !Q_stricmp( string, "localhost" ) || !Q_stricmp( string, "loopback" ))
{
adr->type = NA_LOOPBACK;
return NET_EAI_OK;
}
res = NET_StringToSockaddr( string, &s, true, AF_UNSPEC );
res = NET_StringToSockaddr( string, &s, true, v6only ? AF_INET6 : AF_UNSPEC );
if( res == NET_EAI_OK )
NET_SockadrToNetadr( &s, adr );
@@ -1759,7 +1746,7 @@ static int NET_IPSocket( const char *net_iface, int port, int family )
if( COM_CheckStringEmpty( net_iface ) && Q_stricmp( net_iface, "localhost" ))
NET_StringToSockaddr( net_iface, &addr, false, AF_INET6 );
else memcpy(((struct sockaddr_in6 *)&addr)->sin6_addr.s6_addr, &in6addr_any, sizeof( struct in6_addr ));
else ((struct sockaddr_in6 *)&addr)->sin6_addr = in6addr_any;
if( port == PORT_ANY ) ((struct sockaddr_in6 *)&addr)->sin6_port = 0;
else ((struct sockaddr_in6 *)&addr)->sin6_port = htons((short)port);
@@ -2092,7 +2079,7 @@ NET_ClearLagData
clear fakelag list
====================
*/
void NET_ClearLagData( qboolean bClient, qboolean bServer )
static void NET_ClearLagData( qboolean bClient, qboolean bServer )
{
if( bClient ) NET_ClearLaggedList( &net.lagdata[NS_CLIENT] );
if( bServer ) NET_ClearLaggedList( &net.lagdata[NS_SERVER] );
@@ -2118,6 +2105,7 @@ void NET_Init( void )
Cvar_RegisterVariable( &net_clientport );
Cvar_RegisterVariable( &net_fakelag );
Cvar_RegisterVariable( &net_fakeloss );
Cvar_RegisterVariable( &net_resolve_debug );
Q_snprintf( cmd, sizeof( cmd ), "%i", PORT_SERVER );
Cvar_FullSet( "hostport", cmd, FCVAR_READ_ONLY );

View File

@@ -66,7 +66,7 @@ qboolean NET_IsReservedAdr( netadr_t a );
qboolean NET_CompareClassBAdr( const netadr_t a, const netadr_t b );
qboolean NET_StringToAdr( const char *string, netadr_t *adr );
qboolean NET_StringToFilterAdr( const char *s, netadr_t *adr, uint *prefixlen );
net_gai_state_t NET_StringToAdrNB( const char *string, netadr_t *adr );
net_gai_state_t NET_StringToAdrNB( const char *string, netadr_t *adr, qboolean v6only );
int NET_CompareAdrSort( const void *_a, const void *_b );
qboolean NET_CompareAdr( const netadr_t a, const netadr_t b );
qboolean NET_CompareBaseAdr( const netadr_t a, const netadr_t b );
@@ -74,7 +74,6 @@ qboolean NET_CompareAdrByMask( const netadr_t a, const netadr_t b, uint prefixle
qboolean NET_GetPacket( netsrc_t sock, netadr_t *from, byte *data, size_t *length );
void NET_SendPacket( netsrc_t sock, size_t length, const void *data, netadr_t to );
void NET_SendPacketEx( netsrc_t sock, size_t length, const void *data, netadr_t to, size_t splitsize );
void NET_ClearLagData( qboolean bClient, qboolean bServer );
void NET_IP6BytesToNetadr( netadr_t *adr, const uint8_t *ip6 );
void NET_NetadrToIP6Bytes( uint8_t *ip6, const netadr_t *adr );

View File

@@ -18,8 +18,10 @@ GNU General Public License for more details.
#define NET_PSVITA_H
#include <vitasdk.h>
#include "platform/posix/net.h"
/* we're missing IPv6 support; define some trash */
#define XASH_NO_IPV6_RESOLVE 1
#ifndef IN6_IS_ADDR_V4MAPPED
#define IN6_IS_ADDR_V4MAPPED( p ) ( 0 )

View File

@@ -5115,6 +5115,8 @@ void SV_SpawnEntities( const char *mapname )
void SV_UnloadProgs( void )
{
pending_cvar_t *pending_cvars_list;
if( !svgame.hInstance )
return;
@@ -5124,6 +5126,8 @@ void SV_UnloadProgs( void )
/// SV_UnloadProgs will be disabled
//Mod_ClearUserData ();
pending_cvars_list = Cvar_PrepareToUnlink( FCVAR_EXTDLL );
if( svgame.dllFuncs2.pfnGameShutdown != NULL )
svgame.dllFuncs2.pfnGameShutdown ();
@@ -5141,7 +5145,7 @@ void SV_UnloadProgs( void )
// must unlink all game cvars,
// before pointers on them will be lost...
Cvar_Unlink( FCVAR_EXTDLL );
Cvar_UnlinkPendingCvars( pending_cvars_list );
Cmd_Unlink( CMD_SERVERDLL );
SV_FreeStringPool();

View File

@@ -288,7 +288,6 @@ const char* Q_timestamp( int format )
static string timestamp;
time_t crt_time;
const struct tm *crt_tm;
string timestring;
time( &crt_time );
crt_tm = localtime( &crt_time );
@@ -297,33 +296,31 @@ const char* Q_timestamp( int format )
{
case TIME_FULL:
// Build the full timestamp (ex: "Apr03 2007 [23:31.55]");
strftime( timestring, sizeof( timestring ), "%b%d %Y [%H:%M.%S]", crt_tm );
strftime( timestamp, sizeof( timestamp ), "%b%d %Y [%H:%M.%S]", crt_tm );
break;
case TIME_DATE_ONLY:
// Build the date stamp only (ex: "Apr03 2007");
strftime( timestring, sizeof( timestring ), "%b%d %Y", crt_tm );
strftime( timestamp, sizeof( timestamp ), "%b%d %Y", crt_tm );
break;
case TIME_TIME_ONLY:
// Build the time stamp only (ex: "23:31.55");
strftime( timestring, sizeof( timestring ), "%H:%M.%S", crt_tm );
strftime( timestamp, sizeof( timestamp ), "%H:%M.%S", crt_tm );
break;
case TIME_NO_SECONDS:
// Build the time stamp exclude seconds (ex: "13:46");
strftime( timestring, sizeof( timestring ), "%H:%M", crt_tm );
strftime( timestamp, sizeof( timestamp ), "%H:%M", crt_tm );
break;
case TIME_YEAR_ONLY:
// Build the date stamp year only (ex: "2006");
strftime( timestring, sizeof( timestring ), "%Y", crt_tm );
strftime( timestamp, sizeof( timestamp ), "%Y", crt_tm );
break;
case TIME_FILENAME:
// Build a timestamp that can use for filename (ex: "Nov2006-26 (19.14.28)");
strftime( timestring, sizeof( timestring ), "%b%Y-%d_%H.%M.%S", crt_tm );
strftime( timestamp, sizeof( timestamp ), "%b%Y-%d_%H.%M.%S", crt_tm );
break;
default: return NULL;
}
Q_strncpy( timestamp, timestring, sizeof( timestamp ));
return timestamp;
}