- create LaunchInfo.txt by default

- when suggesting a command, don't add full path (since it will be found in
  $PATH anyway)
- clean up resolve_path. Let it do path and tilde expansion and don't suggest
  directories in $PATH.
- fix some minor memory leaks
- export the variables XQF_SERVER_NAME, XQF_SERVER_MAP, XQF_SERVER_HOSTNAME and
  XQF_SERVER_GAME when launching a game (suggested by Ruediger Meier)


git-svn-id: http://svn.code.sf.net/p/xqf/code/trunk@611 d2ac09be-c843-0410-8b1f-f8a84130e0ec
This commit is contained in:
Ludwig Nussel 2004-05-09 12:45:59 +00:00 committed by l-n
parent 9ac88211c2
commit f8eb8b2728
6 changed files with 381 additions and 107 deletions

View File

@ -1,3 +1,13 @@
May 09, 2004: Ludwig Nussel <l-n@users.sourceforge.net>
- create LaunchInfo.txt by default
- when suggesting a command, don't add full path (since it will be found in
$PATH anyway)
- clean up resolve_path. Let it do path and tilde expansion and don't suggest
directories in $PATH.
- fix some minor memory leaks
- export the variables XQF_SERVER_NAME, XQF_SERVER_MAP, XQF_SERVER_HOSTNAME and
XQF_SERVER_GAME when launching a game (suggested by Ruediger Meier)
May 08, 2004: Ludwig Nussel <l-n@users.sourceforge.net>
- support for Half-Life steam master. Nasty hack, hopefully doesn't break other stuff.
- set anti-cheat flag for VAC (secure != 0)

View File

@ -275,8 +275,20 @@ int client_launch_exec (int forkit, char *dir, char* argv[],
else { /* child */
close (pipefds[0]);
if( s->flags & SERVER_PUNKBUSTER )
setenv("XQF_SERVER_ANTICHEAT","1",1);
if(s->flags & SERVER_PUNKBUSTER)
setenv("XQF_SERVER_ANTICHEAT", "1", 1);
if(s->name)
setenv("XQF_SERVER_NAME", s->name, 1);
if(s->map)
setenv("XQF_SERVER_MAP", s->map, 1);
if(s->host->name)
setenv("XQF_SERVER_HOSTNAME", s->host->name, 1);
if(s->game)
setenv("XQF_SERVER_GAME", s->game, 1);
execvp (argv[0], argv);

View File

@ -1940,9 +1940,8 @@ static GtkWidget *create_noskins_menu (int qworq2) {
// fill working directory with result of the directory guess function for first
// token of command line if working directory is empty
static void pref_guess_dir(enum server_type type)
static void pref_guess_dir(enum server_type type, const char* cmdline, gboolean interactive)
{
const char *cmdline = NULL;
const char* dir_entry = NULL;
dir_entry = gtk_entry_get_text (GTK_ENTRY (genprefs[type].dir_entry));
@ -1950,7 +1949,6 @@ static void pref_guess_dir(enum server_type type)
if(dir_entry && *dir_entry)
return;
cmdline = gtk_entry_get_text (GTK_ENTRY (genprefs[type].cmd_entry));
if (cmdline && *cmdline) // if not empty
{
char *guessed_dir = NULL;
@ -1972,7 +1970,8 @@ static void pref_guess_dir(enum server_type type)
g_strfreev(cmds);
}
dialog_ok (NULL, _("You must configure a command line first"));
if(interactive)
dialog_ok (NULL, _("You must configure a command line first"));
}
@ -1998,7 +1997,7 @@ static void pref_suggest_command(enum server_type type)
return;
}
suggested_file = find_file_in_path(files);
suggested_file = find_file_in_path_relative(files);
if(!suggested_file)
{
dialog_ok(_("Game not found"),
@ -2010,9 +2009,10 @@ static void pref_suggest_command(enum server_type type)
// gtk entry does the freeing? -- no
gtk_entry_set_text (GTK_ENTRY (genprefs[type].cmd_entry), suggested_file);
g_free(suggested_file);
pref_guess_dir (type);
pref_guess_dir (type, suggested_file, TRUE);
g_free(suggested_file);
return;
}
@ -2335,10 +2335,9 @@ static GtkWidget *generic_game_frame (enum server_type type) {
gtk_widget_show (button);
// translator: button for directory guess
button = gtk_button_new_with_label (_("Guess"));
button = gtk_button_new_with_label (_("Suggest"));
gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
GTK_SIGNAL_FUNC (game_file_activate_callback), (gpointer)type);
// GTK_SIGNAL_FUNC (pref_guess_dir), (gpointer)type);
gtk_box_pack_start (GTK_BOX (hbox),button , FALSE, FALSE, 0);
gtk_tooltips_set_tip (tooltips, button, _("Tries to guess the working directory based on the command line"), NULL);
@ -4539,6 +4538,8 @@ static void generic_prefs_free(struct generic_prefs* prefs)
for (i = 0; i < GAMES_TOTAL; i++)
{
g_free(prefs[i].pref_dir);
g_free(prefs[i].real_dir);
g_datalist_clear(&prefs[i].games_data);
}
g_free(prefs);
@ -4725,7 +4726,7 @@ static void user_fix_defaults (void)
{
files = games[i].suggest_commands;
if(!files) continue;
suggested_file = find_file_in_path(files);
suggested_file = find_file_in_path_relative(files);
if(!suggested_file) continue;
j++;
@ -5007,7 +5008,7 @@ int prefs_load (void) {
default_terminate = config_get_bool ("terminate=false");
default_iconify = config_get_bool ("iconify=false");
default_launchinfo = config_get_bool ("launchinfo=false");
default_launchinfo = config_get_bool ("launchinfo=true");
default_stopxmms = config_get_bool ("stopxmms=false");
default_prelaunchexec = config_get_bool ("prelaunchexec=false");
default_save_lists = config_get_bool ("save lists=true");
@ -5089,18 +5090,19 @@ void prefs_save (void) {
void game_file_dialog_ok_callback (GtkWidget *widget, GtkFileSelection *fs)
{
enum server_type type;
char *temp = NULL;
char *filename = NULL;
type = (int) gtk_object_get_user_data (GTK_OBJECT (widget));
type = (enum server_type) gtk_object_get_user_data (GTK_OBJECT (widget));
if(type >= UNKNOWN_SERVER)
return;
temp = g_strdup(gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs)));
filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs));
if (temp) {
gtk_entry_set_text (GTK_ENTRY (genprefs[type].cmd_entry), temp);
pref_guess_dir (type);
if (filename) {
gtk_entry_set_text (GTK_ENTRY (genprefs[type].cmd_entry), filename);
pref_guess_dir (type, filename, TRUE);
}
if (temp)
g_free (temp);
}
void game_file_activate_callback (enum server_type type)
@ -5108,19 +5110,11 @@ void game_file_activate_callback (enum server_type type)
char *temp = NULL;
char *file = NULL;
temp = g_strdup(gtk_entry_get_text (GTK_ENTRY (genprefs[type].cmd_entry)));
temp = gtk_entry_get_text (GTK_ENTRY (genprefs[type].cmd_entry));
if (temp) {
file = find_file_in_path(temp);
if (file)
gtk_entry_set_text (GTK_ENTRY (genprefs[type].cmd_entry), file);
}
pref_guess_dir (type, temp, TRUE);
pref_guess_dir (type);
if (temp)
g_free (temp);
if (file)
g_free (file);
g_free (file);
}
void game_dir_dialog_ok_callback (GtkWidget *widget, GtkFileSelection *fs)

View File

@ -19,21 +19,132 @@
#include "gnuconfig.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include "utils.h"
#include "debug.h"
#define PRINT(fmt,rest...) \
printf("%s: " fmt "\n", __FUNCTION__, ##rest)
#define ERROR(fmt,rest...) \
PRINT(fmt ": %s", ##rest, strerror(errno))
typedef enum { tFile, tSymlink, tDirecory } FileType;
typedef struct
{
FileType type;
char name[PATH_MAX];
} File;
enum { MaxFiles = 255 };
static File* tempfiles[MaxFiles] = {0};
static int currentFile = 0;
#define BASEDIR "/tmp/xqf_test_util/"
static void popFile(int nr)
{
for( ; nr > 0 && currentFile > 0 ; --nr)
{
File* entry = tempfiles[--currentFile];
if(!entry)
continue;
switch(entry->type)
{
case tFile:
case tSymlink:
if(unlink(entry->name) == -1)
{
ERROR("unlink %s", entry->name);
}
break;
case tDirecory:
if(rmdir(entry->name) == -1)
{
ERROR("rmdir %s", entry->name);
}
break;
}
g_free(entry);
}
if(currentFile < 0)
currentFile = 0;
}
static void cleanup()
{
popFile(currentFile);
}
static const char* newFile(FileType type, const char* name)
{
File* f = NULL;
if(currentFile >= MaxFiles)
exit(1);
f = tempfiles[currentFile] = g_malloc0(sizeof(File));
f->type = type;
strcpy(f->name, BASEDIR);
strcat(f->name, name);
++currentFile;
return f->name;
}
static void doMkdir(const char* dir)
{
dir = newFile(tDirecory, dir);
if(mkdir(dir, 0755) == -1)
{
ERROR("mkdir %s", dir);
exit(1);
}
}
static void doSymlink(const char* oldpath, const char* newpath)
{
newpath = newFile(tSymlink, newpath);
if(symlink(oldpath, newpath) == -1)
{
ERROR("symlink %s -> %s", newpath, oldpath);
exit(1);
}
}
static void doFile(const char* name)
{
int fd = -1;
name = newFile(tFile, name);
if((fd = open(name, O_CREAT|O_EXCL|O_RDWR, 0755)) == -1)
{
ERROR("open %s", name);
exit(1);
}
close(fd);
}
void test_find_game_dir()
{
const char* basedir = "/usr/local/games/quake3";
const char* targets[] =
{
"westernq3",
"WESTERNQ3",
"triBALctf",
"Q3UT2",
"Q3UT3",
"ABC",
NULL
};
@ -42,12 +153,21 @@ void test_find_game_dir()
int type = 0;
int i = 0;
doMkdir("westernq3");
doMkdir("WESTERNQ3");
doMkdir("tribalctf");
doMkdir("q3ut3");
doSymlink("q3ut2", "Q3UT2");
doSymlink("q3ut3", "Q3UT3");
for(; targets[i]; ++i)
{
result = find_game_dir(basedir, targets[i], &type);
result = find_game_dir(BASEDIR, targets[i], &type);
PRINT("search %s, result %s, type %d", targets[i], result, type);
g_free(result);
}
popFile(6);
}
void test_file_in_dir()
@ -75,14 +195,63 @@ void test_file_in_dir()
}
}
void test_resolve_path()
{
char buf[PATH_MAX] = {0};
char* oldpath = NULL;
const char* files[] =
{
"binarypath", // binary in $PATH
"relative", // relative symlink
"absolute", // absolute symlink
"noexist", // not existing
BASEDIR "bin/binarypath",
BASEDIR "bin/relative",
BASEDIR "bin/absolute",
BASEDIR "bin/noexist",
BASEDIR "game/binary",
"~/bin/bla",
"~/bin/q3",
NULL
};
int i = 0;
doMkdir("game");
doMkdir("bin");
doFile("game/binary");
doFile("bin/binarypath");
doSymlink("../game/binary", "bin/relative");
doSymlink(BASEDIR "game/binary", "bin/absolute");
oldpath = getenv("PATH");
if(!oldpath)
exit(1);
snprintf(buf, sizeof(buf), "%s%s:%s", BASEDIR, "bin", oldpath);
setenv("PATH", buf, 1);
for(; files[i]; ++i)
{
char* path = resolve_path(files[i]);
PRINT("'%s' -> '%s'", files[i], path);
g_free(path);
}
setenv("PATH", oldpath, 1);
}
int main (int argc, char* argv[])
{
atexit(cleanup);
doMkdir("");
set_debug_level(0);
test_find_game_dir();
test_file_in_dir();
test_resolve_path();
return 0;
exit(0);
}
// vim: sw=4

View File

@ -36,6 +36,7 @@
#include "debug.h"
#include "i18n.h"
static char* find_file_in_path2(const char* files, gboolean relative);
short strtosh (const char *str) {
long tmp;
@ -520,6 +521,16 @@ const char* bool2str(int i)
* must be freed manually
*/
char* find_file_in_path(const char* files)
{
return find_file_in_path2(files, FALSE);
}
char* find_file_in_path_relative(const char* files)
{
return find_file_in_path2(files, TRUE);
}
static char* find_file_in_path2(const char* files, gboolean relative)
{
char** binaries = NULL;
char* path = NULL;
@ -548,7 +559,7 @@ char* find_file_in_path(const char* files)
{
// If directory name is blank, don't add a / - happens if
// a complete path was passed
if (strlen(directories[j]))
if (!relative && strlen(directories[j]))
found = g_strconcat(directories[j],"/",binaries[i],NULL);
else
found = g_strdup(binaries[i]);
@ -558,6 +569,7 @@ char* find_file_in_path(const char* files)
}
}
g_strfreev(directories);
g_strfreev(binaries);
return found;
@ -692,83 +704,152 @@ GSList* slist_sort_remove_dups(GSList* list, GCompareFunc compare_func, void (*u
return list;
}
/** \brief determine directory for game binary
*
* Extracts the path from path using the following rules:
* - If path is a symlink:
* - If pointed to file contains '..', just stop, otherwise strip filename and
* store as directory
* - If there is no /'s in the pointed to file, use the original path instead and
* strip filename and store as directory
*
* - If path is not a symlink:
* - strip filename and store as directory
*
* Path can be either a file or a directory
*
* Examples:
*
* path: /usr/bin/quake2 symlink to /games/quake2/quake2
* result: /games/quake2/
*
* path: /usr/bin/quake symlink to ../../games/quake2/quake2
* result: (stops - leaves as-is)
*
* path: /games/quake2/quake2
* result: /games/quake2/
*
* path: quake2
* result: search $PATH for binary then use above rules
*
* path: ~/bin/quake2
* result: expand tilde then use above rules
*
* @returns game direcory or NULL. must be freed
*/
char* resolve_path(const char* path)
{
// Extracts the path from path using the following rules:
// - If path is a symlink:
// - If pointed to file contains '..', just stop, otherwise strip filename and
// store as directory
// - If there is no /'s in the pointed to file, use the original cmd_entry instead and
// strip filename and store as directory
//
// - If path is not a symlink:
// - strip filename and store as directory
//
// Path can be either a file or a directory
//
// Examples:
//
// cmd_entry: /usr/bin/quake2 symlink to /games/quake2/quake2
// result dir: /games/quake2/
//
// cmd_entry: /usr/bin/quake symlink to ../../games/quake2/quake2
// result dir: (stops - leaves as-is)
//
// cmd_entry: /games/quake2/quake2
// result dir: /games/quake2/
//
// cmd_entry: quake2
// result dir: (stops - leaves as-is)
//
struct stat buf;
struct stat statbuf;
int length = 0;
char buf2[256];
char buf[256];
char *ptr = NULL;
char *dir = NULL;
char* tmp = NULL;
if (strcmp (path, "")) {
lstat(path, &buf);
if ( S_ISLNK(buf.st_mode) == 1) {
// Grab directory from sym link of cmd_entry
debug(2, "path is a sym link");
if(!path || !*path)
return NULL;
length = readlink (path, buf2, 255);
if (length){
buf2[length]='\0';
if(buf2[length-1] == '/')
buf2[length-1] = '\0';
ptr = strrchr(buf2, '/');
if (ptr) { // contains a / so pull from symlink
if (!strstr(buf2,"..")) { // don't bother if it's got any ..'s in it
dir = g_strndup(buf2, ptr-buf2+1);
}
}
else { // no / so pull from cmd_entry instead
ptr = strrchr(path, '/');
if (ptr) { // contains a /
dir = g_strndup(path, ptr-path+1);
}
}
}
}
else {
// Grab directory from cmd_entry
debug(2,"path is NOT a sym link");
ptr = strrchr(path, '/');
if (ptr) { // contains a /
dir = g_strndup(path, ptr-path+1);
}
}
if(path[0] == '~')
{
tmp = expand_tilde(path);
path = tmp;
}
else if(path[0] != '/')
{
tmp = find_file_in_path(path);
if(!tmp)
{
debug(3, "%s not found in $PATH", path);
return NULL;
}
path = tmp;
}
if(lstat(path, &statbuf) == -1)
{
debug(3, "lstat on %s failed", path);
g_free(tmp);
return NULL;
}
if ( S_ISLNK(statbuf.st_mode) == 1)
{
// Grab directory from sym link of cmd_entry
debug(3, "path is a sym link");
length = readlink (path, buf, sizeof(buf) - 1);
if (length > 0)
{
buf[length]='\0';
if(buf[length-1] == '/')
buf[length-1] = '\0';
ptr = strrchr(buf, '/');
if (ptr) { // contains a / so pull from symlink
if (!strstr(buf,"..")) { // don't bother if it's got any ..'s in it
dir = g_strndup(buf, ptr-buf+1);
}
}
else { // no / so pull from path instead
ptr = strrchr(path, '/');
if (ptr) { // contains a /
dir = g_strndup(path, ptr-path+1);
}
}
}
}
else
{
// Grab directory from cmd_entry
debug(3,"path is NOT a sym link");
ptr = strrchr(path, '/');
if (ptr) // contains a /
{
gboolean dir_is_path = FALSE;
char* PATH = getenv("PATH");
// ignore direcory if it is in $PATH. It doesn't make sense to suggest
// /usr/bin as game direcory
if(PATH)
{
int i;
char** directories = g_strsplit(PATH,":",0);
char* basedir = g_strndup(path, ptr-path);
for(i=0; directories[i]; ++i)
{
if(!strcmp(directories[i], basedir))
{
dir_is_path = TRUE;
break;
}
}
g_strfreev(directories);
g_free(basedir);
}
if(!dir_is_path)
{
dir = tmp;
tmp = NULL;
}
else
debug(3, "found directory %s in $PATH, ignoring", tmp);
}
}
g_free(tmp);
return dir;
}

View File

@ -77,12 +77,20 @@ const char* bool2str(int i);
int str2bool(const char* str);
/** find executable file in $PATH. file is a colon seperated list of
* executables to search for. return name of first found file, must be freed
* manually
/** \brief find executable file in $PATH.
*
* @param files colon seperated list of executables to search for
* @returns absolute path to first found file, must be freed manually
*/
char* find_file_in_path(const char* files);
/** \brief find executable file in $PATH.
*
* @param files colon seperated list of executables to search for
* @returns first found file, must be freed manually
*/
char* find_file_in_path_relative(const char* files);
/** sort list and remove duplicates
* @param list list to sort
* @compare_func function to use for comparing