2007-11-04 03:51:54 +00:00
/*
2012-03-17 20:01:54 +00:00
Copyright ( C ) 1999 - 2007 id Software , Inc . and contributors .
For a list of contributors , see the accompanying CONTRIBUTORS file .
2007-11-04 03:51:54 +00:00
2012-03-17 20:01:54 +00:00
This file is part of GtkRadiant .
2007-11-04 03:51:54 +00:00
2012-03-17 20:01:54 +00:00
GtkRadiant is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
2007-11-04 03:51:54 +00:00
2012-03-17 20:01:54 +00:00
GtkRadiant is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
2007-11-04 03:51:54 +00:00
2012-03-17 20:01:54 +00:00
You should have received a copy of the GNU General Public License
along with GtkRadiant ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
2007-11-04 03:51:54 +00:00
2023-04-17 16:13:50 +00:00
# if defined( __linux__ ) || defined( __BSD__ ) || defined( __APPLE__ )
2007-11-04 03:51:54 +00:00
# include <gdk/gdkx.h>
# include <pwd.h>
2008-06-26 07:52:02 +00:00
# include <unistd.h>
2007-11-04 03:51:54 +00:00
# ifdef __linux__
2012-03-17 20:01:54 +00:00
# include <mntent.h>
2007-11-04 03:51:54 +00:00
# endif
# include <dirent.h>
# include <pthread.h>
# include <sys/wait.h>
# include <signal.h>
# include <sys/stat.h>
2013-09-14 14:06:39 +00:00
# include <fcntl.h>
2007-11-04 03:51:54 +00:00
# endif
# include <gtk/gtk.h>
2010-11-26 19:50:08 +00:00
# include <gtk/gtkgl.h>
2008-06-26 07:52:02 +00:00
# include <glib/gi18n.h>
2007-11-04 03:51:54 +00:00
# include "stdafx.h"
# include <assert.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <stdlib.h>
# include "watchbsp.h"
# include "filters.h"
2010-11-26 19:50:08 +00:00
# include "glwidget.h"
2007-11-04 03:51:54 +00:00
bool g_bBuildList = false ;
int g_argc ;
char * * g_argv ;
2012-05-17 12:11:03 +00:00
// =============================================================================
// Windows WinMain() wrapper for main()
// used in Release Builds to suppress the Console
# if defined(_WIN32)
# include <winbase.h>
int main ( int argc , char * argv [ ] ) ;
int CALLBACK WinMain (
__in HINSTANCE hInstance ,
__in HINSTANCE hPrevInstance ,
__in LPSTR lpCmdLine ,
__in int nCmdShow
) {
2012-05-17 12:14:34 +00:00
return main ( __argc , __argv ) ;
2012-05-17 12:11:03 +00:00
}
# endif
2012-12-19 02:42:33 +00:00
//============================================================================
// Splash Screen
//============================================================================
2007-11-04 03:51:54 +00:00
// get rid of it when debugging
2012-03-17 20:01:54 +00:00
# if defined ( _DEBUG )
2007-11-04 03:51:54 +00:00
# define SKIP_SPLASH
# endif
static GtkWidget * splash_screen ;
2012-12-19 02:42:33 +00:00
// called based on a timer, or in particular cases when we don't want to
// keep it around
2012-03-17 20:01:54 +00:00
gint try_destroy_splash ( gpointer data ) {
if ( splash_screen ) {
gtk_widget_destroy ( splash_screen ) ;
splash_screen = NULL ;
}
return FALSE ;
2007-11-04 03:51:54 +00:00
}
2013-07-07 13:22:34 +00:00
# ifndef SKIP_SPLASH
2012-12-19 02:42:33 +00:00
static void create_splash ( ) {
splash_screen = gtk_window_new ( GTK_WINDOW_TOPLEVEL ) ;
2017-03-16 11:40:56 +00:00
gtk_window_set_title ( GTK_WINDOW ( splash_screen ) , _ ( " Splash Screen " ) ) ;
2012-12-19 02:42:33 +00:00
gtk_container_set_border_width ( GTK_CONTAINER ( splash_screen ) , 0 ) ;
gtk_widget_set_size_request ( splash_screen , 640 , 384 ) ;
gtk_window_set_keep_above ( GTK_WINDOW ( splash_screen ) , TRUE ) ;
gtk_window_set_decorated ( GTK_WINDOW ( splash_screen ) , FALSE ) ;
gtk_window_set_position ( GTK_WINDOW ( splash_screen ) , GTK_WIN_POS_CENTER ) ;
gtk_window_set_resizable ( GTK_WINDOW ( splash_screen ) , FALSE ) ;
CString str = g_strBitmapsPath ;
str + = " splash.png " ;
GtkWidget * image = gtk_image_new_from_file ( str . GetBuffer ( ) ) ;
gtk_container_add ( GTK_CONTAINER ( splash_screen ) , image ) ;
gtk_widget_show_all ( splash_screen ) ;
while ( gtk_events_pending ( ) )
2012-03-17 20:01:54 +00:00
gtk_main_iteration ( ) ;
2007-11-04 03:51:54 +00:00
}
2013-07-07 13:22:34 +00:00
# endif
2007-11-04 03:51:54 +00:00
// =============================================================================
// Loki stuff
2023-04-17 16:13:50 +00:00
# if defined( __linux__ ) || defined( __BSD__ ) || defined( __APPLE__ )
2007-11-04 03:51:54 +00:00
/* The directory where the data files can be found (run directory) */
static char datapath [ PATH_MAX ] ;
2023-02-19 21:35:05 +00:00
# ifdef __linux__
2007-11-04 03:51:54 +00:00
/* Code to determine the mount point of a CD-ROM */
2012-03-17 20:01:54 +00:00
int loki_getmountpoint ( const char * device , char * mntpt , int max_size ) {
char devpath [ PATH_MAX ] , mntdevpath [ PATH_MAX ] ;
FILE * mountfp ;
struct mntent * mntent ;
int mounted ;
/* Nothing to do with no device file */
if ( device = = NULL ) {
* mntpt = ' \0 ' ;
return - 1 ;
}
/* Get the fully qualified path of the CD-ROM device */
if ( realpath ( device , devpath ) = = NULL ) {
perror ( " realpath() on your CD-ROM failed " ) ;
return ( - 1 ) ;
}
/* Get the mount point */
mounted = - 1 ;
memset ( mntpt , 0 , max_size ) ;
mountfp = setmntent ( _PATH_MNTTAB , " r " ) ;
if ( mountfp ! = NULL ) {
mounted = 0 ;
while ( ( mntent = getmntent ( mountfp ) ) ! = NULL )
{
char * tmp , mntdev [ 1024 ] ;
strcpy ( mntdev , mntent - > mnt_fsname ) ;
if ( strcmp ( mntent - > mnt_type , " supermount " ) = = 0 ) {
tmp = strstr ( mntent - > mnt_opts , " dev= " ) ;
if ( tmp ) {
strcpy ( mntdev , tmp + strlen ( " dev= " ) ) ;
tmp = strchr ( mntdev , ' , ' ) ;
if ( tmp ) {
* tmp = ' \0 ' ;
}
}
}
if ( strncmp ( mntdev , " /dev " , 4 ) | |
realpath ( mntdev , mntdevpath ) = = NULL ) {
continue ;
}
if ( strcmp ( mntdevpath , devpath ) = = 0 ) {
mounted = 1 ;
assert ( ( int ) strlen ( mntent - > mnt_dir ) < max_size ) ;
strncpy ( mntpt , mntent - > mnt_dir , max_size - 1 ) ;
mntpt [ max_size - 1 ] = ' \0 ' ;
break ;
}
}
endmntent ( mountfp ) ;
}
return ( mounted ) ;
2008-06-26 07:52:02 +00:00
}
2023-02-19 21:35:05 +00:00
# endif
2007-11-04 03:51:54 +00:00
2008-06-26 07:52:02 +00:00
/*
2007-11-04 03:51:54 +00:00
This function gets the directory containing the running program .
argv0 - the 0 ' th argument to the program
2012-03-17 20:01:54 +00:00
*/
2023-04-24 03:50:22 +00:00
void loki_init_datapath ( char * argv0 ) {
2023-02-19 21:35:05 +00:00
char temppath [ PATH_MAX ] ;
2023-04-24 03:50:22 +00:00
const char * home ;
2023-02-19 21:35:05 +00:00
home = g_get_home_dir ( ) ;
2012-03-17 20:01:54 +00:00
if ( home = = NULL ) {
2023-04-24 03:50:22 +00:00
home = " . " ;
2012-03-17 20:01:54 +00:00
}
2023-02-19 21:35:05 +00:00
strcpy ( temppath , argv0 ) ;
2012-03-17 20:01:54 +00:00
/* Now canonicalize it to a full pathname for the data path */
if ( realpath ( temppath , datapath ) ) {
2023-02-19 21:35:05 +00:00
/* There should always be '/' in the path, cut after so we end our directories with a slash */
* ( strrchr ( datapath , ' / ' ) + 1 ) = ' \0 ' ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:51:54 +00:00
}
# endif
// end of Loki stuff
// =============================================================================
2012-03-17 20:01:54 +00:00
void error_redirect ( const gchar * domain , GLogLevelFlags log_level , const gchar * message , gpointer user_data ) {
gboolean in_recursion ;
gboolean is_fatal ;
char buf [ 256 ] ;
2023-04-24 03:53:46 +00:00
memset ( buf , 0 , sizeof ( buf ) ) ;
2012-03-17 20:01:54 +00:00
in_recursion = ( log_level & G_LOG_FLAG_RECURSION ) ! = 0 ;
is_fatal = ( log_level & G_LOG_FLAG_FATAL ) ! = 0 ;
log_level = ( GLogLevelFlags ) ( log_level & G_LOG_LEVEL_MASK ) ;
if ( ! message ) {
message = " (NULL) message " ;
}
if ( domain ) {
2023-04-24 03:53:46 +00:00
strncpy ( buf , domain , sizeof ( buf ) - 1 ) ;
2012-03-17 20:01:54 +00:00
}
2023-04-24 03:53:46 +00:00
else {
strncpy ( buf , " ** " , sizeof ( buf ) - 1 ) ;
2012-03-17 20:01:54 +00:00
}
2023-04-24 03:53:46 +00:00
strncat ( buf , " - " , sizeof ( buf ) - strlen ( buf ) - 1 ) ;
2012-03-17 20:01:54 +00:00
switch ( log_level )
{
case G_LOG_LEVEL_ERROR :
if ( in_recursion ) {
2023-04-24 03:53:46 +00:00
strncat ( buf , " ERROR (recursed) **: " , sizeof ( buf ) - strlen ( buf ) - 1 ) ;
2012-03-17 20:01:54 +00:00
}
else {
2023-04-24 03:53:46 +00:00
strncat ( buf , " ERROR **: " , sizeof ( buf ) - strlen ( buf ) - 1 ) ;
2012-03-17 20:01:54 +00:00
}
break ;
case G_LOG_LEVEL_CRITICAL :
if ( in_recursion ) {
2023-04-24 03:53:46 +00:00
strncat ( buf , " CRITICAL (recursed) **: " , sizeof ( buf ) - strlen ( buf ) - 1 ) ;
2012-03-17 20:01:54 +00:00
}
else {
2023-04-24 03:53:46 +00:00
strncat ( buf , " CRITICAL **: " , sizeof ( buf ) - strlen ( buf ) - 1 ) ;
2012-03-17 20:01:54 +00:00
}
break ;
case G_LOG_LEVEL_WARNING :
if ( in_recursion ) {
2023-04-24 03:53:46 +00:00
strncat ( buf , " WARNING (recursed) **: " , sizeof ( buf ) - strlen ( buf ) - 1 ) ;
2012-03-17 20:01:54 +00:00
}
else {
2023-04-24 03:53:46 +00:00
strncat ( buf , " WARNING **: " , sizeof ( buf ) - strlen ( buf ) - 1 ) ;
2012-03-17 20:01:54 +00:00
}
break ;
case G_LOG_LEVEL_MESSAGE :
if ( in_recursion ) {
2023-04-24 03:53:46 +00:00
strncat ( buf , " Message (recursed): " , sizeof ( buf ) - strlen ( buf ) - 1 ) ;
2012-03-17 20:01:54 +00:00
}
else {
2023-04-24 03:53:46 +00:00
strncat ( buf , " Message: " , sizeof ( buf ) - strlen ( buf ) - 1 ) ;
2012-03-17 20:01:54 +00:00
}
break ;
case G_LOG_LEVEL_INFO :
if ( in_recursion ) {
2023-04-24 03:53:46 +00:00
strncat ( buf , " INFO (recursed): " , sizeof ( buf ) - strlen ( buf ) - 1 ) ;
2012-03-17 20:01:54 +00:00
}
else {
2023-04-24 03:53:46 +00:00
strncat ( buf , " INFO: " , sizeof ( buf ) - strlen ( buf ) - 1 ) ;
2012-03-17 20:01:54 +00:00
}
break ;
case G_LOG_LEVEL_DEBUG :
if ( in_recursion ) {
2023-04-24 03:53:46 +00:00
strncat ( buf , " DEBUG (recursed): " , sizeof ( buf ) - strlen ( buf ) - 1 ) ;
2012-03-17 20:01:54 +00:00
}
else {
2023-04-24 03:53:46 +00:00
strncat ( buf , " DEBUG: " , sizeof ( buf ) - strlen ( buf ) - 1 ) ;
2012-03-17 20:01:54 +00:00
}
break ;
default :
/* we are used for a log level that is not defined by GLib itself,
* try to make the best out of it .
*/
if ( in_recursion ) {
2023-04-24 03:53:46 +00:00
strncat ( buf , " LOG (recursed: " , sizeof ( buf ) - strlen ( buf ) - 1 ) ;
2012-03-17 20:01:54 +00:00
}
else {
2023-04-24 03:53:46 +00:00
strncat ( buf , " LOG ( " , sizeof ( buf ) - strlen ( buf ) - 1 ) ;
2012-03-17 20:01:54 +00:00
}
if ( log_level ) {
gchar string [ ] = " 0x00): " ;
gchar * p = string + 2 ;
guint i ;
i = g_bit_nth_msf ( log_level , - 1 ) ;
* p = i > > 4 ;
p + + ;
* p = ' 0 ' + ( i & 0xf ) ;
if ( * p > ' 9 ' ) {
* p + = ' A ' - ' 9 ' - 1 ;
}
2023-04-24 03:53:46 +00:00
strncat ( buf , string , sizeof ( buf ) - strlen ( buf ) - 1 ) ;
2012-03-17 20:01:54 +00:00
}
else {
2023-04-24 03:53:46 +00:00
strncat ( buf , " ): " , sizeof ( buf ) - strlen ( buf ) - 1 ) ;
2012-03-17 20:01:54 +00:00
}
}
2023-04-24 03:53:46 +00:00
strncat ( buf , message , sizeof ( buf ) - strlen ( buf ) - 1 ) ;
2012-03-17 20:01:54 +00:00
if ( is_fatal ) {
2023-04-24 03:53:46 +00:00
strncat ( buf , " \n aborting... \n " , sizeof ( buf ) - strlen ( buf ) - 1 ) ;
} else {
strncat ( buf , " \n " , sizeof ( buf ) - strlen ( buf ) - 1 ) ;
2012-03-17 20:01:54 +00:00
}
2023-04-24 03:53:46 +00:00
printf ( " %s " , buf ) ;
Sys_FPrintf ( SYS_WRN , " %s " , buf ) ;
2012-03-17 20:01:54 +00:00
// TTimo NOTE: in some cases it may be handy to log only to the file
2007-11-04 03:51:54 +00:00
// Sys_FPrintf (SYS_NOCON, buf);
}
2008-06-26 08:31:13 +00:00
# define GETTEXT_PACKAGE "radiant"
# define LOCALEDIR "lang"
2016-04-11 20:16:12 +00:00
int mainRadiant ( int argc , char * argv [ ] ) {
2013-05-03 06:57:29 +00:00
const char * libgl ;
2007-12-25 00:10:45 +00:00
int i , j , k ;
2007-11-04 03:51:54 +00:00
2015-09-26 20:47:39 +00:00
# if defined( _WIN32 ) && defined( _MSC_VER )
//increase the max open files to its maximum for the C run-time of MSVC
_setmaxstdio ( 2048 ) ;
# endif
2012-03-17 20:01:54 +00:00
/*
Rambetter on Sat Nov 13 , 2010 :
The following line fixes parsing and writing of floating point numbers in locales such as
Italy , Germany , and others outside of en_US . In particular , in such problem locales , users
are not able to use certain map entities such as " light " because the definitions of these entities
in the entity definition files contain floating point values written in the standard " C " format
( containing a dot instead of , for example , a comma ) . The call sscanf ( ) is all over the code ,
including parsing entity definition files and reading Radiant preferences . sscanf ( ) is sensitive
to locale ( in particular when reading floating point numbers ) .
The line below is the minimalistic way to address only this particular problem - the parsing
and writing of floating point values . There may be other yet - undiscovered bugs related to
locale still lingering in the code . When such bugs are discovered , they should be addressed by
setting more than just " LC_NUMERIC=C " ( for example LC_CTYPE for regular expression matching )
or by fixing the problem in the actual code instead of fiddling with LC_ * variables .
Another way to fix the floating point format problem is to locate all calls such as * scanf ( )
and * printf ( ) in the code and replace them with other functions . However , we ' re also using
external libraries such as libxml and [ maybe ? ] they use locale to parse their numeric values .
I ' m just saying , it may get ugly if we try to fix the problem without setting LC_NUMERIC .
Usage of sscanf ( ) throughout the code looks like so :
sscanf ( str , " %f %f %f " , & val1 , & val2 , & val3 ) ;
Code like this exists in many files , here are 4 examples :
tools / quake3 / q3map2 / light . c
tools / quake3 / q3map2 / model . c
radiant / preferences . cpp
plugins / entity / miscmodel . cpp
Also affected are printf ( ) calls when using formats that contain " %f " .
I did some research and putenv ( ) seems to be the best choice for being cross - platform . It
used to be a function in Windows ( now deprecated ) :
http : //msdn.microsoft.com/en-us/library/ms235321(VS.80).aspx
And of course it ' s defined in UNIX .
One more thing . the gtk_init ( ) call below modifies all of the locale settings . In fact if it
weren ' t for gtk_init ( ) , we wouldn ' t have to set LC_NUMERIC ( parsing of floating points with
a dot works just fine before the gtk_init ( ) call on a sample Linux system ) . If we were to
just setlocale ( ) here , it would get clobbered by gtk_init ( ) . So instead of using setlocale ( )
_after_ gtk_init ( ) , I chose to fix this problem via environment variable . I think it ' s cleaner
that way .
*/
2013-07-07 13:22:34 +00:00
putenv ( ( char * ) " LC_NUMERIC=C " ) ;
2010-11-14 01:40:25 +00:00
2013-06-27 20:02:47 +00:00
// Use the same environment variable for resolving libGL as libgtkglext does.
libgl = getenv ( " GDK_GL_LIBGL_PATH " ) ;
if ( libgl = = NULL ) {
2023-04-17 16:13:50 +00:00
# if defined ( _WIN32 )
libgl = " opengl32.dll " ;
# elif defined ( __linux__ ) || defined ( __FreeBSD__ )
libgl = " libGL.so.1 " ;
# elif defined ( __OpenBSD__ )
libgl = " libGL.so.18.0 " ;
# elif defined( __NetBSD__ )
libgl = " libGL.so.3.0 " ;
# elif defined ( __APPLE__ )
libgl = " /opt/local/lib/libGL.dylib " ;
# else
# error unknown architecture
# endif
2013-06-27 20:02:47 +00:00
}
2007-11-04 03:51:54 +00:00
2023-04-17 16:13:50 +00:00
# if defined( __linux__ ) || defined( __BSD__ ) || defined( __APPLE__ )
2012-03-17 20:01:54 +00:00
// Give away unnecessary root privileges.
// Important: must be done before calling gtk_init().
char * loginname ;
struct passwd * pw ;
seteuid ( getuid ( ) ) ;
if ( geteuid ( ) = = 0 & & ( loginname = getlogin ( ) ) ! = NULL & & ( pw = getpwnam ( loginname ) ) ! = NULL ) {
setuid ( pw - > pw_uid ) ;
}
2007-11-04 03:51:54 +00:00
# endif
2008-06-26 08:31:13 +00:00
2012-03-17 20:01:54 +00:00
bindtextdomain ( GETTEXT_PACKAGE , LOCALEDIR ) ;
bind_textdomain_codeset ( GETTEXT_PACKAGE , " UTF-8 " ) ;
textdomain ( GETTEXT_PACKAGE ) ;
2008-06-26 08:31:13 +00:00
// gtk_disable_setlocale();
2007-11-04 03:51:54 +00:00
2012-03-17 20:01:54 +00:00
gtk_init ( & argc , & argv ) ;
gtk_gl_init ( & argc , & argv ) ;
gdk_gl_init ( & argc , & argv ) ;
// TODO: Find a better place to call this.
gtk_glwidget_create_font ( ) ;
for ( i = 1 ; i < argc ; i + + )
{
char * param = argv [ i ] ;
if ( param [ 0 ] = = ' - ' & & param [ 1 ] = = ' - ' ) {
param + = 2 ;
2013-06-29 14:17:08 +00:00
if ( strcmp ( param , " builddefs " ) = = 0 ) {
2012-03-17 20:01:54 +00:00
g_bBuildList = true ;
argv [ i ] = NULL ;
}
}
}
for ( i = 1 ; i < argc ; i + + )
{
for ( k = i ; k < argc ; k + + )
if ( argv [ k ] ! = NULL ) {
break ;
}
if ( k > i ) {
k - = i ;
for ( j = i + k ; j < argc ; j + + )
argv [ j - k ] = argv [ j ] ;
argc - = k ;
}
}
g_argc = argc ;
g_argv = argv ;
g_strPluginsDir = " plugins/ " ;
g_strModulesDir = " modules/ " ;
2007-11-04 03:51:54 +00:00
# ifdef _WIN32
2012-03-17 20:01:54 +00:00
// get path to the editor
char * pBuffer = g_strAppPath . GetBufferSetLength ( _MAX_PATH + 1 ) ;
GetModuleFileName ( NULL , pBuffer , _MAX_PATH ) ;
pBuffer [ g_strAppPath . ReverseFind ( ' \\ ' ) + 1 ] = ' \0 ' ;
QE_ConvertDOSToUnixName ( pBuffer , pBuffer ) ;
g_strAppPath . ReleaseBuffer ( ) ;
2023-03-13 03:04:02 +00:00
g_strGamesPath = g_strAppPath ;
2023-02-20 03:23:57 +00:00
2012-03-17 20:01:54 +00:00
g_strBitmapsPath = g_strAppPath ;
g_strBitmapsPath + = " bitmaps/ " ;
CGameDialog : : UpdateNetrun ( false ) ; // read the netrun configuration
if ( CGameDialog : : GetNetrun ( ) ) {
// we have to find a per-user g_strTempPath
// this behaves the same as on Linux
g_strTempPath = getenv ( " USERPROFILE " ) ;
if ( ! g_strTempPath . GetLength ( ) ) {
CString msg ;
2017-03-16 11:40:56 +00:00
msg = _ ( " Radiant is configured to run from a network installation. \n " ) ;
msg + = _ ( " I couldn't find the environement variable USERPROFILE \n " ) ;
msg + = _ ( " I'm going to use C: \\ RadiantSettings. Please set USERPROFILE \n " ) ;
gtk_MessageBox ( NULL , msg , _ ( " Radiant - Network mode " ) , MB_OK ) ;
2012-03-17 20:01:54 +00:00
g_strTempPath = " C: \\ " ;
}
g_strTempPath + = " \\ RadiantSettings \\ " ;
Q_mkdir ( g_strTempPath . GetBuffer ( ) , 0755 ) ;
g_strTempPath + = RADIANT_VERSION ;
g_strTempPath + = " \\ " ;
Q_mkdir ( g_strTempPath . GetBuffer ( ) , 0755 ) ;
}
else
{
// use the core path as temp (to save commandlist.txt, and do the .pid files)
g_strTempPath = g_strAppPath ;
}
2007-11-04 03:51:54 +00:00
# endif
2023-04-17 16:13:50 +00:00
# if defined( __linux__ ) || defined( __BSD__ ) || defined( __APPLE__ )
2023-02-19 21:35:05 +00:00
const char * xdg_state_home = getenv ( " XDG_STATE_HOME " ) ;
if ( xdg_state_home ! = nullptr ) {
g_strTempPath = xdg_state_home ;
} else {
g_strTempPath = g_get_home_dir ( ) ;
2012-03-17 20:01:54 +00:00
}
2023-02-19 21:35:05 +00:00
g_strTempPath + = " /.radiant/ " ;
Q_mkdir ( g_strTempPath . GetBuffer ( ) , 0775 ) ;
g_strTempPath + = RADIANT_VERSION ;
Q_mkdir ( g_strTempPath . GetBuffer ( ) , 0775 ) ;
AddSlash ( g_strTempPath ) ;
2012-03-17 20:01:54 +00:00
2023-02-19 21:35:05 +00:00
loki_init_datapath ( argv [ 0 ] ) ;
2023-04-24 03:50:22 +00:00
g_strAppPath = datapath ;
2012-03-17 20:01:54 +00:00
2023-02-20 03:23:57 +00:00
const char * xdg_data_home = getenv ( " XDG_DATA_HOME " ) ;
if ( xdg_data_home ! = nullptr ) {
g_strGamesPath = xdg_data_home ;
g_strGamesPath + = " / " ;
} else {
g_strGamesPath = g_strAppPath ;
}
g_strGamesPath + = " games/ " ;
Q_mkdir ( g_strGamesPath . GetBuffer ( ) , 0775 ) ;
2012-03-17 20:01:54 +00:00
// radiant is installed in the parent dir of "tools/"
// NOTE: this is not very easy for debugging
// maybe add options to lookup in several places?
// (for now I had to create symlinks)
g_strBitmapsPath = g_strAppPath ;
g_strBitmapsPath + = " bitmaps/ " ;
// we will set this right after the game selection is done
g_strGameToolsPath = g_strAppPath ;
2007-11-04 03:51:54 +00:00
# endif
2012-03-17 20:01:54 +00:00
// init the DTD path
g_strDTDPath = g_strAppPath ;
g_strDTDPath + = " dtds/ " ;
/*!
the global prefs loading / game selection dialog might fail for any reason we don ' t know about
we need to catch when it happens , to cleanup the stateful prefs which might be killing it
and to turn on console logging for lookup of the problem
this is the first part of the two step . pid system
*/
g_pidFile = g_strTempPath . GetBuffer ( ) ;
g_pidFile + = " radiant.pid " ;
FILE * pid ;
pid = fopen ( g_pidFile . GetBuffer ( ) , " r " ) ;
if ( pid ! = NULL ) {
fclose ( pid ) ;
CString msg ;
if ( remove ( g_pidFile . GetBuffer ( ) ) = = - 1 ) {
2017-03-16 11:40:56 +00:00
msg = _ ( " WARNING: Could not delete " ) ; msg + = g_pidFile ;
gtk_MessageBox ( NULL , msg , _ ( " Radiant " ) , MB_OK | MB_ICONERROR ) ;
2012-03-17 20:01:54 +00:00
}
// in debug, never prompt to clean registry, turn console logging auto after a failed start
# if !defined( _DEBUG )
2017-03-16 11:40:56 +00:00
msg = _ ( " Found the file " ) ;
2012-03-17 20:01:54 +00:00
msg + = g_pidFile ;
2017-03-16 11:40:56 +00:00
msg + = _ ( " . \n This indicates that Radiant failed during the game selection startup last time it was run. \n "
2012-03-17 20:01:54 +00:00
" Choose YES to clean Radiant's registry settings and shut down Radiant. \n "
2017-03-16 11:40:56 +00:00
" WARNING: the global prefs will be lost if you choose YES. " ) ;
2012-03-17 20:01:54 +00:00
2017-03-16 11:40:56 +00:00
if ( gtk_MessageBox ( NULL , msg , _ ( " Radiant - Reset global startup? " ) , MB_YESNO | MB_ICONQUESTION ) = = IDYES ) {
2012-03-17 20:01:54 +00:00
// remove global prefs and shutdown
g_PrefsDlg . mGamesDialog . Reset ( ) ;
// remove the prefs file (like a full reset of the registry)
//remove (g_PrefsDlg.m_inipath->str);
2017-03-16 11:40:56 +00:00
gtk_MessageBox ( NULL , _ ( " Removed global settings, choose OK to close Radiant. " ) , _ ( " Radiant " ) , MB_OK ) ;
2012-03-17 20:01:54 +00:00
_exit ( - 1 ) ;
}
2017-03-16 11:40:56 +00:00
msg = _ ( " Logging console output to " ) ;
2012-03-17 20:01:54 +00:00
msg + = g_strTempPath ;
2017-03-16 11:40:56 +00:00
msg + = _ ( " radiant.log \n Refer to the log if Radiant fails to start again. " ) ;
2012-03-17 20:01:54 +00:00
2017-03-16 11:40:56 +00:00
gtk_MessageBox ( NULL , msg , _ ( " Radiant - Console Log " ) , MB_OK ) ;
2007-11-04 03:51:54 +00:00
# endif
2012-03-17 20:01:54 +00:00
// set without saving, the class is not in a coherent state yet
// just do the value change and call to start logging, CGamesDialog will pickup when relevant
g_PrefsDlg . mGamesDialog . m_bLogConsole = true ;
g_PrefsDlg . mGamesDialog . m_bForceLogConsole = true ;
Sys_LogFile ( ) ;
}
// create a primary .pid for global init run
pid = fopen ( g_pidFile . GetBuffer ( ) , " w " ) ;
if ( pid ) {
fclose ( pid ) ;
}
// a safe check to avoid people running broken installations
// (otherwise, they run it, crash it, and blame us for not forcing them hard enough to pay attention while installing)
// make something idiot proof and someone will make better idiots, this may be overkill
// let's leave it disabled in debug mode in any case
2007-11-04 03:51:54 +00:00
# ifndef _DEBUG
2012-03-17 20:01:54 +00:00
//#define CHECK_VERSION
2007-11-04 03:51:54 +00:00
# endif
2008-06-26 07:52:02 +00:00
# ifdef CHECK_VERSION
2012-03-17 20:01:54 +00:00
// locate and open RADIANT_MAJOR and RADIANT_MINOR
qboolean bVerIsGood = true ;
Str ver_file_name ;
ver_file_name = g_strAppPath ;
ver_file_name + = " RADIANT_MAJOR " ;
FILE * ver_file = fopen ( ver_file_name . GetBuffer ( ) , " r " ) ;
if ( ver_file ) {
char buf [ 10 ] ;
int chomp ;
fread ( buf , 1 , 10 , ver_file ) ;
// chomp it (the hard way)
chomp = 0 ;
while ( buf [ chomp ] > = ' 0 ' & & buf [ chomp ] < = ' 9 ' )
chomp + + ;
buf [ chomp ] = ' \0 ' ;
if ( strcmp ( buf , RADIANT_MAJOR_VERSION ) ) {
2016-05-16 19:20:20 +00:00
Sys_FPrintf ( SYS_ERR , " ERROR: file RADIANT_MAJOR doesn't match ('%s') \n " , buf ) ;
2012-03-17 20:01:54 +00:00
bVerIsGood = false ;
}
}
else
{
2016-05-16 19:20:20 +00:00
Sys_FPrintf ( SYS_ERR , " ERROR: can't find RADIANT_MAJOR in '%s' \n " , ver_file_name . GetBuffer ( ) ) ;
2012-03-17 20:01:54 +00:00
bVerIsGood = false ;
}
ver_file_name = g_strAppPath ;
ver_file_name + = " RADIANT_MINOR " ;
ver_file = fopen ( ver_file_name . GetBuffer ( ) , " r " ) ;
if ( ver_file ) {
char buf [ 10 ] ;
int chomp ;
fread ( buf , 1 , 10 , ver_file ) ;
// chomp it (the hard way)
chomp = 0 ;
while ( buf [ chomp ] > = ' 0 ' & & buf [ chomp ] < = ' 9 ' )
chomp + + ;
buf [ chomp ] = ' \0 ' ;
if ( strcmp ( buf , RADIANT_MINOR_VERSION ) ) {
2016-05-16 19:20:20 +00:00
Sys_FPrintf ( SYS_ERR , " ERROR: file RADIANT_MINOR doesn't match ('%s') \n " , buf ) ;
2012-03-17 20:01:54 +00:00
bVerIsGood = false ;
}
}
else
{
2016-05-16 19:20:20 +00:00
Sys_FPrintf ( SYS_ERR , " ERROR: can't find RADIANT_MINOR in '%s' \n " , ver_file_name . GetBuffer ( ) ) ;
2012-03-17 20:01:54 +00:00
bVerIsGood = false ;
}
if ( ! bVerIsGood ) {
CString msg ;
msg = " This editor binary ( " RADIANT_VERSION " ) doesn't match what the latest setup has configured in this directory \n " ;
msg + = " Make sure you run the right/latest editor binary you installed \n " ;
msg + = g_strAppPath ; msg + = " \n " ;
msg + = " Check http://www.qeradiant.com/faq/index.cgi?file=219 for more information " ;
2017-03-16 11:40:56 +00:00
gtk_MessageBox ( NULL , msg . GetBuffer ( ) , _ ( " Radiant " ) , MB_OK , " http://www.qeradiant.com/faq/index.cgi?file=219 " ) ;
2012-03-17 20:01:54 +00:00
_exit ( - 1 ) ;
}
2007-11-04 03:51:54 +00:00
# endif
2008-06-26 07:52:02 +00:00
2012-03-17 20:01:54 +00:00
g_qeglobals . disable_ini = false ;
g_PrefsDlg . Init ( ) ;
// close the primary
if ( remove ( g_pidFile . GetBuffer ( ) ) = = - 1 ) {
CString msg ;
2017-03-16 11:40:56 +00:00
msg = _ ( " WARNING: Could not delete " ) ; msg + = g_pidGameFile ;
gtk_MessageBox ( NULL , msg , _ ( " Radiant " ) , MB_OK | MB_ICONERROR ) ;
2012-03-17 20:01:54 +00:00
}
/*!
now the secondary game dependant . pid file
*/
g_pidGameFile = g_PrefsDlg . m_rc_path - > str ;
g_pidGameFile + = " radiant-game.pid " ;
pid = fopen ( g_pidGameFile . GetBuffer ( ) , " r " ) ;
if ( pid ! = NULL ) {
fclose ( pid ) ;
CString msg ;
if ( remove ( g_pidGameFile . GetBuffer ( ) ) = = - 1 ) {
2017-03-16 11:40:56 +00:00
msg = _ ( " WARNING: Could not delete " ) ; msg + = g_pidGameFile ;
gtk_MessageBox ( NULL , msg , _ ( " Radiant " ) , MB_OK | MB_ICONERROR ) ;
2012-03-17 20:01:54 +00:00
}
2017-03-16 11:40:56 +00:00
msg = _ ( " Found the file " ) ;
2012-03-17 20:01:54 +00:00
msg + = g_pidGameFile ;
2017-03-16 11:40:56 +00:00
msg + = _ ( " . \n This indicates that Radiant failed to load the last time it was run. \n "
2012-03-17 20:01:54 +00:00
" Choose YES to clean Radiant's registry settings and shut down Radiant. \n "
2017-03-16 11:40:56 +00:00
" WARNING: preferences will be lost if you choose YES. " ) ;
2012-03-17 20:01:54 +00:00
// in debug, never prompt to clean registry, turn console logging auto after a failed start
# if !defined( _DEBUG )
//bleh
2017-03-16 11:40:56 +00:00
if ( gtk_MessageBox ( NULL , msg , _ ( " Radiant - Clean Registry? " ) , MB_YESNO | MB_ICONQUESTION ) = = IDYES ) {
2012-03-17 20:01:54 +00:00
// remove the game prefs files
remove ( g_PrefsDlg . m_inipath - > str ) ;
char buf [ PATH_MAX ] ;
sprintf ( buf , " %sSavedInfo.bin " , g_PrefsDlg . m_rc_path - > str ) ;
remove ( buf ) ;
// remove the global pref too
g_PrefsDlg . mGamesDialog . Reset ( ) ;
2017-03-16 11:40:56 +00:00
gtk_MessageBox ( NULL , _ ( " Cleaned registry settings, choose OK to close Radiant. \n The next time Radiant runs it will use default settings. " ) , _ ( " Radiant " ) , MB_OK ) ;
2012-03-17 20:01:54 +00:00
_exit ( - 1 ) ;
}
2017-03-16 11:40:56 +00:00
msg = _ ( " Logging console output to " ) ;
2012-03-17 20:01:54 +00:00
msg + = g_strTempPath ;
2017-03-16 11:40:56 +00:00
msg + = _ ( " radiant.log \n Refer to the log if Radiant fails to start again. " ) ;
2012-03-17 20:01:54 +00:00
2017-03-16 11:40:56 +00:00
gtk_MessageBox ( NULL , msg , _ ( " Radiant - Console Log " ) , MB_OK ) ;
2007-11-04 03:51:54 +00:00
# endif
2012-03-17 20:01:54 +00:00
// force console logging on! (will go in prefs too)
g_PrefsDlg . mGamesDialog . m_bLogConsole = true ;
g_PrefsDlg . mGamesDialog . SavePrefs ( ) ;
Sys_LogFile ( ) ;
2007-11-04 03:51:54 +00:00
2012-03-17 20:01:54 +00:00
g_PrefsDlg . LoadPrefs ( ) ;
2007-11-04 03:51:54 +00:00
2012-03-17 20:01:54 +00:00
}
else
{
// create one, will remove right after entering message loop
pid = fopen ( g_pidGameFile . GetBuffer ( ) , " w " ) ;
if ( pid ) {
fclose ( pid ) ;
}
2007-11-04 03:51:54 +00:00
2012-03-17 20:01:54 +00:00
g_PrefsDlg . LoadPrefs ( ) ;
2007-11-04 03:51:54 +00:00
# ifndef _DEBUG // I can't be arsed about that prompt in debug mode
2012-03-17 20:01:54 +00:00
// if console logging is on in the prefs, warn about performance hit
if ( g_PrefsDlg . mGamesDialog . m_bLogConsole ) {
2017-03-16 11:40:56 +00:00
if ( gtk_MessageBox ( NULL , _ ( " Preferences indicate that console logging is on. This affects performance. \n "
" Turn it off? " ) , _ ( " Radiant " ) , MB_YESNO | MB_ICONQUESTION ) = = IDYES ) {
2012-03-17 20:01:54 +00:00
g_PrefsDlg . mGamesDialog . m_bLogConsole = false ;
g_PrefsDlg . mGamesDialog . SavePrefs ( ) ;
}
}
2007-11-04 03:51:54 +00:00
# endif
2012-03-17 20:01:54 +00:00
// toggle console logging if necessary
Sys_LogFile ( ) ;
}
2007-11-04 03:51:54 +00:00
2012-03-17 20:01:54 +00:00
// we should search in g_strTempPath, then move over to look at g_strAppPath?
2007-11-04 03:51:54 +00:00
# ifdef _WIN32
2012-03-17 20:01:54 +00:00
// fine tune the look of the app using a gtk rc file
// we try to load an RC file placed in the application directory
// build the full path
Str sRCFile ;
sRCFile = g_strAppPath ;
sRCFile + = " radiantgtkrc " ;
// we load that file with g_new in gtk_rc_parse_file (gtkrc.c), change the '/' into '\\'
pBuffer = ( char * ) sRCFile . GetBuffer ( ) ;
for ( i = 0 ; i < sRCFile . GetLength ( ) ; i + + )
{
if ( pBuffer [ i ] = = ' / ' ) {
pBuffer [ i ] = ' \\ ' ;
}
}
// check the file exists
if ( access ( sRCFile . GetBuffer ( ) , R_OK ) ! = 0 ) {
Sys_Printf ( " RC file %s not found \n " , sRCFile . GetBuffer ( ) ) ;
}
else
{
Sys_Printf ( " Attemping to load RC file %s \n " , sRCFile . GetBuffer ( ) ) ;
gtk_rc_parse ( sRCFile . GetBuffer ( ) ) ;
}
2007-11-04 03:51:54 +00:00
# endif
# ifndef SKIP_SPLASH
2012-03-17 20:01:54 +00:00
create_splash ( ) ;
2007-11-04 03:51:54 +00:00
# endif
2012-03-17 20:01:54 +00:00
if ( ! QGL_Init ( libgl , " " ) ) {
Sys_FPrintf ( SYS_ERR , " Failed to load OpenGL libraries \n " ) ;
_exit ( 1 ) ;
return 1 ;
}
2023-04-17 16:13:50 +00:00
# if defined( __linux__ ) || defined( __BSD__ ) || defined( __APPLE__ )
2017-05-27 23:09:56 +00:00
if ( ( qglXQueryExtension = = NULL ) | | ( qglXQueryExtension ( gdk_x11_get_default_xdisplay ( ) , NULL , NULL ) ! = True ) ) {
2012-03-17 20:01:54 +00:00
Sys_FPrintf ( SYS_ERR , " glXQueryExtension failed \n " ) ;
_exit ( 1 ) ;
return 1 ;
}
2007-11-04 03:51:54 +00:00
# endif
2012-03-17 20:01:54 +00:00
// redirect Gtk warnings to the console
g_log_set_handler ( " Gdk " , ( GLogLevelFlags ) ( G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING |
G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG ) , error_redirect , NULL ) ;
g_log_set_handler ( " Gtk " , ( GLogLevelFlags ) ( G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING |
G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG ) , error_redirect , NULL ) ;
2007-11-04 03:51:54 +00:00
2012-03-17 20:01:54 +00:00
// spog - creates new filters list for the first time
g_qeglobals . d_savedinfo . filters = NULL ;
g_qeglobals . d_savedinfo . filters = FilterAddBase ( g_qeglobals . d_savedinfo . filters ) ;
2007-11-04 03:51:54 +00:00
2012-03-17 20:01:54 +00:00
g_pParentWnd = new MainFrame ( ) ;
2007-11-04 03:51:54 +00:00
2012-05-04 08:02:31 +00:00
// If the first parameter is a .map, load that.
if ( g_argc > 1 & & IsMap ( g_argv [ 1 ] ) ) {
Map_LoadFile ( g_argv [ 1 ] ) ;
}
else if ( g_PrefsDlg . m_bLoadLastMap & & g_PrefsDlg . m_strLastMap . GetLength ( ) > 0 ) {
2012-03-17 20:01:54 +00:00
Map_LoadFile ( g_PrefsDlg . m_strLastMap . GetBuffer ( ) ) ;
}
else {
Map_New ( ) ;
}
2007-11-04 03:51:54 +00:00
2012-03-17 20:01:54 +00:00
// load up shaders now that we have the map loaded
// eviltypeguy
Texture_ShowStartupShaders ( ) ;
2007-11-04 03:51:54 +00:00
# ifndef SKIP_SPLASH
2017-03-15 10:58:36 +00:00
gdk_window_raise ( gtk_widget_get_window ( splash_screen ) ) ;
2012-03-17 20:01:54 +00:00
gtk_window_set_transient_for ( GTK_WINDOW ( splash_screen ) , GTK_WINDOW ( g_pParentWnd - > m_pWidget ) ) ;
2017-03-15 10:58:36 +00:00
g_timeout_add ( 1000 , try_destroy_splash , NULL ) ;
2007-11-04 03:51:54 +00:00
# endif
2008-06-26 07:52:02 +00:00
2012-03-17 20:01:54 +00:00
g_pParentWnd - > GetSynapseServer ( ) . DumpActiveClients ( ) ;
2007-11-04 03:51:54 +00:00
2012-03-17 20:01:54 +00:00
//++timo: temporary debug
g_pParentWnd - > DoWatchBSP ( ) ;
2007-11-04 03:51:54 +00:00
2012-03-17 20:01:54 +00:00
gtk_main ( ) ;
2007-11-04 03:51:54 +00:00
2012-03-17 20:01:54 +00:00
// close the log file if any
// NOTE: don't save prefs past this point!
g_PrefsDlg . mGamesDialog . m_bLogConsole = false ;
// set the console window to NULL to avoid Sys_Printf crashing
g_qeglobals_gui . d_edit = NULL ;
Sys_LogFile ( ) ;
2007-11-04 03:51:54 +00:00
2012-03-17 20:01:54 +00:00
// NOTE TTimo not sure what this _exit(0) call is worth
// restricting it to linux build
2007-11-04 03:51:54 +00:00
# ifdef __linux__
2012-03-17 20:01:54 +00:00
_exit ( 0 ) ;
2007-11-04 03:51:54 +00:00
# endif
2012-03-17 20:01:54 +00:00
return 0 ;
2007-11-04 03:51:54 +00:00
}
2016-04-11 20:16:12 +00:00
2017-03-06 13:02:48 +00:00
# if defined( _WIN32 ) && defined( _MSC_VER ) && !defined( _DEBUG )
2016-04-11 20:16:12 +00:00
# include <dbghelp.h>
# include <shellapi.h>
# include <shlobj.h>
# include <strsafe.h> //StringCchPrintf
int GenerateDump ( EXCEPTION_POINTERS * pExceptionPointers ) {
BOOL bMiniDumpSuccessful ;
char szPath [ MAX_PATH ] ;
char szFileName [ MAX_PATH ] ;
char szAppName [ ] = " GTKRadiant " ;
char * szVersion = RADIANT_VERSION ;
DWORD dwBufferSize = MAX_PATH ;
HANDLE hDumpFile ;
SYSTEMTIME stLocalTime ;
MINIDUMP_EXCEPTION_INFORMATION ExpParam ;
GetLocalTime ( & stLocalTime ) ;
GetTempPath ( dwBufferSize , szPath ) ;
StringCchPrintf ( szFileName , MAX_PATH , " %s%s " , szPath , szAppName ) ;
CreateDirectory ( szFileName , NULL ) ;
StringCchPrintf ( szFileName , MAX_PATH , " %s%s \\ %s-%s-%04d%02d%02d-%02d%02d%02d.dmp " ,
szPath , szAppName , szAppName , szVersion ,
stLocalTime . wYear , stLocalTime . wMonth , stLocalTime . wDay ,
stLocalTime . wHour , stLocalTime . wMinute , stLocalTime . wSecond ) ;
hDumpFile = CreateFile ( szFileName , GENERIC_READ | GENERIC_WRITE ,
FILE_SHARE_WRITE | FILE_SHARE_READ , 0 , CREATE_ALWAYS , 0 , 0 ) ;
ExpParam . ThreadId = GetCurrentThreadId ( ) ;
ExpParam . ExceptionPointers = pExceptionPointers ;
ExpParam . ClientPointers = TRUE ;
bMiniDumpSuccessful = MiniDumpWriteDump ( GetCurrentProcess ( ) , GetCurrentProcessId ( ) ,
hDumpFile , MiniDumpWithDataSegs , & ExpParam , NULL , NULL ) ;
return EXCEPTION_EXECUTE_HANDLER ;
}
# endif
int main ( int argc , char * argv [ ] ) {
2017-03-06 13:02:48 +00:00
# if defined( _WIN32 ) && defined( _MSC_VER ) && !defined( _DEBUG )
2016-04-11 20:16:12 +00:00
__try {
return mainRadiant ( argc , argv ) ;
} __except ( GenerateDump ( GetExceptionInformation ( ) ) ) {
char szPath [ MAX_PATH ] ;
char szText [ MAX_PATH ] ;
char szFileName [ MAX_PATH ] ;
char szAppName [ ] = " GTKRadiant " ;
SYSTEMTIME stLocalTime ;
DWORD dwBufferSize = MAX_PATH ;
GetLocalTime ( & stLocalTime ) ;
GetTempPath ( dwBufferSize , szPath ) ;
StringCchPrintf ( szFileName , MAX_PATH , " %s%s " , szPath , szAppName ) ;
StringCchPrintf ( szText , MAX_PATH , _ ( " Application crashed! \n Created a dump file in: \n %s " ) , szFileName ) ;
MessageBox ( NULL , szText , NULL , MB_ICONERROR ) ;
}
# else
return mainRadiant ( argc , argv ) ;
# endif
}
2007-11-04 03:51:54 +00:00
// ydnar: quick and dirty fix, just make the buffer bigger
2012-03-17 20:01:54 +00:00
# define BIG_PATH_MAX 4096
2007-11-04 03:51:54 +00:00
// TTimo: decompose the BSP command into several steps so we can monitor them eventually
2012-03-17 20:01:54 +00:00
void QE_ExpandBspString ( char * bspaction , GPtrArray * out_array , char * mapname ) {
const char * in ;
char * out ;
char src [ BIG_PATH_MAX ] ;
char rsh [ BIG_PATH_MAX ] ;
char base [ BIG_PATH_MAX ] ;
strcpy ( src , mapname ) ;
strlwr ( src ) ;
in = strstr ( src , " maps/ " ) ;
if ( in ) {
in + = 5 ;
strcpy ( base , in ) ;
out = base ;
while ( * out )
{
if ( * out = = ' \\ ' ) {
* out = ' / ' ;
}
out + + ;
}
}
else
{
ExtractFileName ( mapname , base ) ;
}
// this important step alters the map name to add fs_game
// NOTE: it used to add fs_basepath too
// the fs_basepath addition moved to being in the project file during the bug fixing rush
// but it may not have been the right thing to do
// HACK: halflife compiler tools don't support -fs_game
// HACK: neither does JKII/SoF2/ etc..
// do we use & have fs_game?
if ( g_pGameDescription - > mGameFile ! = " hl.game " & &
* ValueForKey ( g_qeglobals . d_project_entity , " gamename " ) ! = ' \0 ' ) {
// set with fs_game
sprintf ( src , " -fs_game %s \" %s \" " , ValueForKey ( g_qeglobals . d_project_entity , " gamename " ) , mapname ) ;
}
else
{
sprintf ( src , " \" %s \" " , mapname ) ;
}
rsh [ 0 ] = 0 ;
QE_ConvertDOSToUnixName ( src , src ) ;
// initialise the first step
2013-09-22 20:53:34 +00:00
out = new char [ BIG_PATH_MAX ] ;
2012-03-17 20:01:54 +00:00
g_ptr_array_add ( out_array , out ) ;
in = ValueForKey ( g_qeglobals . d_project_entity , bspaction ) ;
while ( * in )
{
if ( in [ 0 ] = = ' ! ' ) {
strcpy ( out , rsh ) ;
out + = strlen ( rsh ) ;
in + + ;
continue ;
}
if ( in [ 0 ] = = ' # ' ) {
char tmp [ 2048 ] ;
// we process these only if monitoring
if ( g_PrefsDlg . m_bWatchBSP ) {
// -connect global option (the only global option so far anyway)
strcpy ( tmp , " -connect 127.0.0.1:39000 " ) ;
strcpy ( out , tmp ) ;
out + = strlen ( tmp ) ;
}
in + + ;
continue ;
}
if ( in [ 0 ] = = ' $ ' ) {
// $ expansion
strcpy ( out , src ) ;
out + = strlen ( src ) ;
in + + ;
continue ;
}
if ( in [ 0 ] = = ' @ ' ) {
* out + + = ' " ' ;
in + + ;
continue ;
}
if ( in [ 0 ] = = ' & ' ) {
if ( in [ 1 ] = = ' & ' ) {
// start a new step
* out = 0 ;
in = in + 2 ;
2013-09-22 20:53:34 +00:00
out = new char [ BIG_PATH_MAX ] ;
2012-03-17 20:01:54 +00:00
g_ptr_array_add ( out_array , out ) ;
}
}
* out + + = * in + + ;
}
* out = 0 ;
2007-11-04 03:51:54 +00:00
}
2012-03-17 20:01:54 +00:00
void FindReplace ( CString & strContents , const char * pTag , const char * pValue ) {
if ( strcmp ( pTag , pValue ) = = 0 ) {
return ;
}
for ( int nPos = strContents . Find ( pTag ) ; nPos > = 0 ; nPos = strContents . Find ( pTag ) )
{
int nRightLen = strContents . GetLength ( ) - strlen ( pTag ) - nPos ;
CString strLeft = strContents . Left ( nPos ) ;
CString strRight = strContents . Right ( nRightLen ) ;
strLeft + = pValue ;
strLeft + = strRight ;
strContents = strLeft ;
}
2007-11-04 03:51:54 +00:00
}
// save the map, deals with regioning
2012-03-17 20:01:54 +00:00
void SaveWithRegion ( char * name ) {
strcpy ( name , currentmap ) ;
if ( region_active ) {
// temporary cut the region to save regular map
region_active = false ;
Map_SaveFile ( name , false ) ;
region_active = true ;
StripExtension ( name ) ;
strcat ( name , " .reg " ) ;
}
Map_SaveFile ( name , region_active ) ;
2007-11-04 03:51:54 +00:00
}
2023-04-17 16:13:50 +00:00
# if defined( __linux__ ) || defined( __BSD__ ) || defined( __APPLE__ )
2013-09-14 14:06:39 +00:00
typedef struct {
pid_t pid ;
int status ;
int pipes [ 2 ] ;
} bsp_child_process_t ;
/*
* @ brief A gtk_idle monitor for redirecting stdout and stderr of the BSP
* compiler process to the Radiant console . This is used on UNIX platforms for
* older BSP tools that do not support the XML - based network monitoring found
* in watchbsp . cpp and feedback . cpp .
*/
static gboolean RunBsp_CaptureOutput ( void * data ) {
bsp_child_process_t * process = ( bsp_child_process_t * ) data ;
pid_t pid ;
// if waitpid returns 0, the child process is alive
if ( ( pid = waitpid ( process - > pid , & process - > status , WNOHANG ) ) = = 0 ) {
char text [ 1024 ] ;
ssize_t len ;
if ( ( len = read ( process - > pipes [ 0 ] , text , sizeof ( text ) ) ) > 0 ) {
GtkTextView * view = GTK_TEXT_VIEW ( g_qeglobals_gui . d_edit ) ;
GtkTextBuffer * buffer = gtk_text_view_get_buffer ( view ) ;
if ( buffer ) {
GtkTextIter iter ;
gtk_text_buffer_get_end_iter ( buffer , & iter ) ;
gtk_text_buffer_insert ( buffer , & iter , text , len ) ;
gtk_text_buffer_get_end_iter ( buffer , & iter ) ;
gtk_text_view_scroll_to_iter ( view , & iter , 0.0 , false , 0.0 , 0.0 ) ;
}
}
return true ; // retain the gtk_idle monitor
}
if ( pid = = - 1 ) {
2016-05-16 19:20:20 +00:00
Sys_FPrintf ( SYS_ERR , " ERROR: Failed to wait for %d: %s \n " , process - > pid , strerror ( errno ) ) ;
2013-09-14 14:06:39 +00:00
} else {
Sys_Printf ( " Process %d terminated with status %d \n " , process - > pid , process - > status ) ;
}
close ( process - > pipes [ 0 ] ) ;
close ( process - > pipes [ 1 ] ) ;
free ( process ) ;
return false ; // cancel the gtk_idle monitor
}
2013-09-14 20:47:10 +00:00
# endif
2013-09-14 14:06:39 +00:00
2012-03-17 20:01:54 +00:00
void RunBsp ( char * command ) {
GPtrArray * sys ;
2013-09-22 20:53:34 +00:00
char batpath [ BIG_PATH_MAX ] ;
char name [ BIG_PATH_MAX ] ;
char cWork [ BIG_PATH_MAX ] ;
2012-03-17 20:01:54 +00:00
FILE * hFile ;
unsigned int i ;
SetInspectorMode ( W_CONSOLE ) ;
SaveWithRegion ( name ) ;
const char * rsh = ValueForKey ( g_qeglobals . d_project_entity , " rshcmd " ) ;
if ( rsh = = NULL ) {
CString strPath , strFile ;
ExtractPath_and_Filename ( name , strPath , strFile ) ;
AddSlash ( strPath ) ;
strncpy ( cWork , strPath , 1024 ) ;
strcat ( cWork , strFile ) ;
2013-09-22 20:53:34 +00:00
} else {
2012-03-17 20:01:54 +00:00
strcpy ( cWork , name ) ;
}
// get the array ready
sys = g_ptr_array_new ( ) ;
QE_ExpandBspString ( command , sys , cWork ) ;
if ( g_PrefsDlg . m_bWatchBSP ) {
// grab the file name for engine running
char * bspname = new char [ 1024 ] ;
ExtractFileName ( currentmap , bspname ) ;
StripExtension ( bspname ) ;
g_pParentWnd - > GetWatchBSP ( ) - > DoMonitoringLoop ( sys , bspname ) ;
2013-09-22 20:53:34 +00:00
} else {
2012-03-17 20:01:54 +00:00
// write all the steps in a single BAT / .sh file and run it, don't bother monitoring it
2022-11-14 21:15:32 +00:00
CString strSys = " echo off \n " ;
2012-03-17 20:01:54 +00:00
for ( i = 0 ; i < sys - > len ; i + + )
{
strSys + = ( char * ) g_ptr_array_index ( sys , i ) ;
2022-11-15 16:27:26 +00:00
Sys_Printf ( " \n %s \n " , ( char * ) g_ptr_array_index ( sys , i ) ) ;
2022-11-14 21:15:32 +00:00
strSys + = " \n IF %ERRORLEVEL% NEQ 0 goto error \n " ;
}
strSys + = " \
goto end \ n \
\ n \
: error \ n \
ECHO . \ n \
ECHO . \ n \
ECHO = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = \ n \
ECHO = = = = = = = = = = = BSP STEP FAILED = = = = = = = = = = = \ n \
ECHO = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = \ n \
ECHO . \ n \
\ n \
: end \ n \
pause \ n \
" ;
2012-03-17 20:01:54 +00:00
2023-04-17 16:13:50 +00:00
# if defined( __linux__ ) || defined( __BSD__ ) || defined( __APPLE__ )
2012-03-17 20:01:54 +00:00
// write qe3bsp.sh
2022-11-14 20:13:33 +00:00
sprintf ( batpath , " %sqe3bsp.sh " , g_strTempPath . GetBuffer ( ) ) ;
2012-03-17 20:01:54 +00:00
Sys_Printf ( " Writing the compile script to '%s' \n " , batpath ) ;
hFile = fopen ( batpath , " w " ) ;
if ( ! hFile ) {
Error ( " Can't write to %s " , batpath ) ;
}
fprintf ( hFile , " #!/bin/sh \n \n " ) ;
2012-03-17 21:32:01 +00:00
fprintf ( hFile , " %s " , strSys . GetBuffer ( ) ) ;
2012-03-17 20:01:54 +00:00
fclose ( hFile ) ;
chmod ( batpath , 0744 ) ;
2007-11-04 03:51:54 +00:00
# endif
# ifdef _WIN32
2022-11-14 20:13:33 +00:00
sprintf ( batpath , " %sqe3bsp.bat " , g_strTempPath . GetBuffer ( ) ) ;
2012-03-17 20:01:54 +00:00
Sys_Printf ( " Writing the compile script to '%s' \n " , batpath ) ;
hFile = fopen ( batpath , " w " ) ;
if ( ! hFile ) {
Error ( " Can't write to %s " , batpath ) ;
}
2012-03-17 21:32:01 +00:00
fprintf ( hFile , " %s " , strSys . GetBuffer ( ) ) ;
2012-03-17 20:01:54 +00:00
fclose ( hFile ) ;
2007-11-04 03:51:54 +00:00
# endif
2012-03-17 20:01:54 +00:00
Pointfile_Delete ( ) ;
2023-04-17 16:13:50 +00:00
# if defined( __linux__ ) || defined( __BSD__ ) || defined( __APPLE__ )
2013-09-14 14:06:39 +00:00
bsp_child_process_t * process = ( bsp_child_process_t * ) malloc ( sizeof ( bsp_child_process_t ) ) ;
memset ( process , 0 , sizeof ( * process ) ) ;
pipe ( process - > pipes ) ;
2012-03-17 20:01:54 +00:00
2013-09-14 14:06:39 +00:00
fcntl ( process - > pipes [ 0 ] , F_SETFL , O_NONBLOCK ) ;
fcntl ( process - > pipes [ 1 ] , F_SETFL , O_NONBLOCK ) ;
2012-03-17 20:01:54 +00:00
2013-09-14 14:06:39 +00:00
process - > pid = fork ( ) ;
switch ( process - > pid )
2012-03-17 20:01:54 +00:00
{
case - 1 :
Error ( " CreateProcess failed " ) ;
break ;
case 0 :
2013-09-14 14:06:39 +00:00
close ( process - > pipes [ 0 ] ) ; // close reading end in the child
dup2 ( process - > pipes [ 1 ] , 1 ) ; // send stdout to the pipe
dup2 ( process - > pipes [ 1 ] , 2 ) ; // send stderr to the pipe
execlp ( batpath , batpath , ( char * ) NULL ) ; // execute the script
fprintf ( stderr , " Failed to execute %s: %s " , batpath , strerror ( errno ) ) ;
_exit ( 1 ) ;
2012-03-17 20:01:54 +00:00
break ;
default :
2013-09-14 14:06:39 +00:00
g_idle_add ( RunBsp_CaptureOutput , ( void * ) process ) ;
2012-03-17 20:01:54 +00:00
break ;
}
2007-11-04 03:51:54 +00:00
# endif
# ifdef _WIN32
2012-03-17 20:01:54 +00:00
Sys_Printf ( " Running bsp command... \n " ) ;
2007-11-04 03:51:54 +00:00
2022-11-14 20:28:45 +00:00
Q_Exec ( batpath , NULL , g_strTempPath . GetBuffer ( ) , true ) ;
2007-11-04 03:51:54 +00:00
# endif
2012-03-17 20:01:54 +00:00
}
2022-11-15 16:27:26 +00:00
// free the strings and the array
for ( i = 0 ; i < sys - > len ; i + + ) {
delete [ ] ( char * ) g_ptr_array_index ( sys , i ) ;
}
g_ptr_array_free ( sys , TRUE ) ;
sys = NULL ;
2007-11-04 03:51:54 +00:00
}