diff --git a/sc2/BUGS b/sc2/BUGS index 4b314df4e..aa970967a 100644 --- a/sc2/BUGS +++ b/sc2/BUGS @@ -88,6 +88,17 @@ The bugs reported but not yet verified: together with the ships in the player's fleet, the modules that are drawn inside the flagship are off by one pixel to the left. +- First, I had saved my game while at the planet/scan menu (I do not know + which planet or moon I was on). I loaded it the next day and tried to get + minerals while avoiding various hazards. I managed to get the minerals, but + was hit heavily by the hazards. The moment I pressed Escape, I noticed I + had THIRTEEN empty crew slot circles for the Lander at the time (as opposed + to twelve like it should have) - an extra empty circle appeared to the left + of the bottom row of crew circles. My Lander was not destroyed, and the + minerals I had gathered were still intact and added to my cargo total. + Moreover, the crew of the Vindicator was refilled to my maximum of 50 -- I + had 40 when I saved and loaded at the beginning of this point. " + - < badalex> ok, im in hyper space right? and lets say one of those probes comes to me... so we start the melee and i select a ship, that all works, but after a select a ship the select a diff --git a/sc2/ChangeLog b/sc2/ChangeLog index c8e141f68..a069f4f90 100644 --- a/sc2/ChangeLog +++ b/sc2/ChangeLog @@ -1,4 +1,5 @@ 0.2: +- Put save data and temporary files in a seperate dir - SvdB - Fix OpenGL colors on big-endian CPUs, from Bryce McKinlay - MikMod now loops modules correctly (OpenAL), from Nic - player.fon/42.png corrected, from Parker diff --git a/sc2/TODO b/sc2/TODO index 7d13a4f91..aba22fbd1 100644 --- a/sc2/TODO +++ b/sc2/TODO @@ -88,6 +88,8 @@ Glitches (don't crash the game, medium priority): when compared to 3DO - When there are more than one page of saved supermelee teams, the last entries will be wrong. +- Temp files don't get deleted if the game is exited in full game mode. + (and the temp dir doesn't get deleted if it's not empty) Implementation bugs (low priority): - Scaling code problems: diff --git a/sc2/src/config.h.in b/sc2/src/config.h.in index 9181c6f39..4a2b702e0 100644 --- a/sc2/src/config.h.in +++ b/sc2/src/config.h.in @@ -1,6 +1,33 @@ +/* This file contains some compile-time configuration options for *nix + * systems. + * src/config.h is generated from src/config.h.in by build.sh + * For windows, you'll have to edit src/msvc++/config.h manually + * if you want anything else than the defaults. + */ + +#ifdef WIN32 + /* If we're compiling in windows, we want the other config.h */ +# include "msvc++/config.h" +#endif + +#ifndef _CONFIG_H +#define _CONFIG_H + /* Directory where the UQM game data is located */ #define CONTENTDIR "@CONTENTDIR@" +/* Directory where game data will be stored */ +#define USERDIR "~/.uqm/" + +/* Directory where supermelee teams will be stored */ +#define MELEEDIR USERDIR "teams/" + +/* Directory where save games will be stored */ +#define SAVEDIR USERDIR "save/" + +/* Directory where config files will be stored */ +#define CONFIGDIR USERDIR + /* Defined if words are stored with the most significant byte first */ @WORDS_BIGENDIAN@ @@ -13,3 +40,5 @@ /* Defined if your system has getopt.h */ @HAVE_GETOPT_H@ +#endif /* _CONFIG_H */ + diff --git a/sc2/src/msvc++/UrQuanMasters.dsp b/sc2/src/msvc++/UrQuanMasters.dsp index 0676a74aa..cb02f9f20 100644 --- a/sc2/src/msvc++/UrQuanMasters.dsp +++ b/sc2/src/msvc++/UrQuanMasters.dsp @@ -42,7 +42,7 @@ RSC=rc.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /MD /W3 /GX /O2 /I ".." /I "..\sc2code" /I "..\sc2code\libs" /I "..\sc2code\ships" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D _VW=320 /D _VH=240 /D "HAVE_OPENGL" /D "GFXMODULE_SDL" /D "SOUNDMODULE_OPENAL" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I ".." /I "..\sc2code" /I "..\sc2code\libs" /I "..\sc2code\ships" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D _VW=320 /D _VH=240 /D "HAVE_CONFIG_H" /D "HAVE_OPENGL" /D "GFXMODULE_SDL" /D "SOUNDMODULE_OPENAL" /YX /FD /c # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe @@ -66,7 +66,7 @@ LINK32=link.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I ".." /I "..\sc2code" /I "..\sc2code\libs" /I "..\sc2code\ships" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D _VW=320 /D _VH=240 /D "HAVE_OPENGL" /D "GFXMODULE_SDL" /D "SOUNDMODULE_OPENAL" /FR /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "." /I ".." /I "..\sc2code" /I "..\sc2code\libs" /I "..\sc2code\ships" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D _VW=320 /D _VH=240 /D "HAVE_CONFIG_H" /D "HAVE_OPENGL" /D "GFXMODULE_SDL" /D "SOUNDMODULE_OPENAL" /FR /YX /FD /GZ /c # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe @@ -128,6 +128,22 @@ SOURCE=..\sc2code\libs\decomp\lzh.h SOURCE=..\sc2code\libs\decomp\update.c # End Source File # End Group +# Begin Group "file" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\sc2code\libs\file\dirs.c +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\file\filintrn.h +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\file\temp.c +# End Source File +# End Group # Begin Group "graphics" # PROP Default_Filter "" @@ -682,6 +698,10 @@ SOURCE=..\sc2code\libs\declib.h # End Source File # Begin Source File +SOURCE=..\sc2code\libs\file.h +# End Source File +# Begin Source File + SOURCE=..\sc2code\libs\gfxlib.h # End Source File # Begin Source File diff --git a/sc2/src/msvc++/config.h b/sc2/src/msvc++/config.h new file mode 100644 index 000000000..f481acf2c --- /dev/null +++ b/sc2/src/msvc++/config.h @@ -0,0 +1,39 @@ +/* This file contains some compile-time configuration options for MS Windows + * systems. + * Change the values below if you want anything other than the defaults. + * For *nix systems, src/config.h is used, which is generated by + * build.sh from src/config.h.in. + */ + +#ifndef _CONFIG_H +#define _CONFIG_H + +/* Directory where the UQM game data is located */ +#define CONTENTDIR "../content" + +/* Directory where game data will be stored */ +#define USERDIR "../userdata" + +/* Directory where supermelee teams will be stored */ +#define MELEEDIR USERDIR "teams/" + +/* Directory where save games will be stored */ +#define SAVEDIR USERDIR "save/" + +/* Directory where config files will be stored */ +#define CONFIGDIR USERDIR + +/* Define if words are stored with the most significant byte first */ +#undef WORDS_BIGENDIAN + +/* Defined if your system has strupr of its own */ +#define HAVE_STRUPR + +/* Defined if your system has stricmp of its own */ +#define HAVE_STRICMP + +/* Defined if your system has getopt.h */ +#undef HAVE_GETOPT_H + +#endif /* _CONFIG_H */ + diff --git a/sc2/src/options.c b/sc2/src/options.c index 503e20d3e..300c2f0ff 100644 --- a/sc2/src/options.c +++ b/sc2/src/options.c @@ -20,19 +20,72 @@ * By Mika Kolehmainen. */ +#include #include +#include #include "compiler.h" #include "options.h" +#include "file.h" int optWhichMusic = MUSIC_3DO; +char *configDir, *saveDir, *meleeDir; BOOLEAN optSubtitles = TRUE; -BOOLEAN FileExists (char *filename) +BOOLEAN FileExists (const char *filename) { FILE *fp; - if ((fp = fopen(filename, "rb")) == NULL) + if ((fp = fopen (filename, "rb")) == NULL) return FALSE; fclose (fp); return TRUE; } + +void +prepareConfigDir (void) { + configDir = malloc (PATH_MAX - 13); + if (expandPath (configDir, PATH_MAX - 13, CONFIGDIR) == -1) + { + // Doesn't have to be fatal, but might mess up things when saving + // config files. + fprintf (stderr, "Fatal error: Invalid path to config files.\n"); + exit (EXIT_FAILURE); + } + configDir = realloc (configDir, strlen (configDir) + 1); + + // Create the path upto the config dir, if not already existing. + mkdirhier (configDir); +} + +void +prepareSaveDir (void) { + saveDir = malloc (PATH_MAX - 13); + if (expandPath (saveDir, PATH_MAX - 13, SAVEDIR) == -1) + { + // Doesn't have to be fatal, but might mess up things when saving + // config files. + fprintf (stderr, "Fatal error: Invalid path to config files.\n"); + exit (EXIT_FAILURE); + } + saveDir = realloc (saveDir, strlen (saveDir) + 1); + + // Create the path upto the save dir, if not already existing. + mkdirhier (saveDir); +} + +void +prepareMeleeDir (void) { + meleeDir = malloc (PATH_MAX - 13); + if (expandPath (meleeDir, PATH_MAX - 13, MELEEDIR) == -1) + { + // Doesn't have to be fatal, but might mess up things when saving + // config files. + fprintf (stderr, "Fatal error: Invalid path to config files.\n"); + exit (EXIT_FAILURE); + } + meleeDir = realloc (meleeDir, strlen (meleeDir) + 1); + + // Create the path upto the save dir, if not already existing. + mkdirhier (meleeDir); +} + diff --git a/sc2/src/options.h b/sc2/src/options.h index b9c585108..e82fef0fc 100644 --- a/sc2/src/options.h +++ b/sc2/src/options.h @@ -35,6 +35,15 @@ extern int optWhichMusic; extern BOOLEAN optSubtitles; -BOOLEAN FileExists (char *filename); +BOOLEAN FileExists (const char *filename); + +extern char *configDir; +extern char *meleeDir; +extern char *saveDir; + +void prepareConfigDir(void); +void prepareMeleeDir(void); +void prepareSaveDir(void); #endif + diff --git a/sc2/src/port.h b/sc2/src/port.h index 70efb3f81..95f45fdd4 100644 --- a/sc2/src/port.h +++ b/sc2/src/port.h @@ -1,6 +1,11 @@ +#ifndef _PORT_H +#define _PORT_H + +#include "config.h" + #ifdef WIN32 -#define HAVE_STRICMP -#define HAVE_STRUPR +#define alloca _alloca +#define snprintf _snprintf #endif #ifndef HAVE_STRICMP @@ -11,3 +16,5 @@ char *strupr (char *str); #endif +#endif /* _PORT_H */ + diff --git a/sc2/src/sc2code/Makeinfo b/sc2/src/sc2code/Makeinfo index 605c1a2ae..be0cde3c1 100644 --- a/sc2/src/sc2code/Makeinfo +++ b/sc2/src/sc2code/Makeinfo @@ -7,6 +7,6 @@ uqm_CFILES="battle.c border.c build.c cleanup.c clock.c collide.c comm.c master.c melee.c misc.c oscill.c outfit.c pickmele.c pickship.c plandata.c process.c restart.c save.c settings.c setup.c ship.c shipstat.c shipyard.c sis.c starbase.c - starcon.c starmap.c state.c status.c tactrans.c trans.c - utils.c velocity.c weapon.c" + starcon.c starmap.c state.c status.c tactrans.c + trans.c utils.c velocity.c weapon.c" diff --git a/sc2/src/sc2code/grpinfo.c b/sc2/src/sc2code/grpinfo.c index 8e66c32bf..6d6ca5c0c 100644 --- a/sc2/src/sc2code/grpinfo.c +++ b/sc2/src/sc2code/grpinfo.c @@ -20,6 +20,7 @@ #ifdef HAVE_UNISTD_H #include #endif +#include "file.h" //#define DEBUG @@ -35,7 +36,7 @@ InitGroupInfo (BOOLEAN FirstTime) { PVOID fp; - fp = OpenResFile (RANDGRPINFO_FILE, "wb"); + fp = OpenResFile (tempFilePath (RANDGRPINFO_FILE), "wb"); if (fp) { GROUP_HEADER GH; @@ -48,7 +49,8 @@ InitGroupInfo (BOOLEAN FirstTime) CloseResFile (fp); } - if (FirstTime && (fp = OpenResFile (DEFGRPINFO_FILE, "wb"))) + if (FirstTime && (fp = OpenResFile (tempFilePath (DEFGRPINFO_FILE), + "wb"))) { PutResFileChar (0, fp); @@ -59,8 +61,8 @@ InitGroupInfo (BOOLEAN FirstTime) void UninitGroupInfo (void) { - unlink (DEFGRPINFO_FILE); - unlink (RANDGRPINFO_FILE); + unlink (tempFilePath (DEFGRPINFO_FILE)); + unlink (tempFilePath (RANDGRPINFO_FILE)); } void @@ -347,10 +349,9 @@ GetGroupInfo (DWORD offset, BYTE which_group) { PVOID fp; - fp = OpenResFile ( - offset && which_group ? DEFGRPINFO_FILE : RANDGRPINFO_FILE, - "r+b" - ); + fp = OpenResFile (tempFilePath ( + offset && which_group ? DEFGRPINFO_FILE : RANDGRPINFO_FILE), + "r+b"); if (fp) { BYTE RaceType, NumShips; @@ -386,7 +387,7 @@ GetGroupInfo (DWORD offset, BYTE which_group) fprintf (stderr, "GetGroupInfo: battle groups out of date %u/%u/%u!\n", month_index, day_index, year_index); #endif /* DEBUG */ - fp = OpenResFile (RANDGRPINFO_FILE, "wb"); + fp = OpenResFile (tempFilePath (RANDGRPINFO_FILE), "wb"); GH.NumGroups = 0; GH.star_index = (COUNT)~0; GH.GroupOffset[0] = 0; @@ -615,10 +616,9 @@ PutGroupInfo (DWORD offset, BYTE which_group) { PVOID fp; - fp = OpenResFile ( - offset && which_group ? DEFGRPINFO_FILE : RANDGRPINFO_FILE, - "r+b" - ); + fp = OpenResFile (tempFilePath ( + offset && which_group ? DEFGRPINFO_FILE : RANDGRPINFO_FILE), + "r+b"); if (fp) { GROUP_HEADER GH; diff --git a/sc2/src/sc2code/libs/Makeinfo b/sc2/src/sc2code/libs/Makeinfo index e4c635f98..f00110e05 100644 --- a/sc2/src/sc2code/libs/Makeinfo +++ b/sc2/src/sc2code/libs/Makeinfo @@ -1,2 +1,2 @@ -uqm_SUBDIRS="decomp graphics input math memory resource sound strings task - threads time video" +uqm_SUBDIRS="decomp file graphics input math memory resource sound strings + task threads time video" diff --git a/sc2/src/sc2code/libs/file.h b/sc2/src/sc2code/libs/file.h new file mode 100644 index 000000000..996bab270 --- /dev/null +++ b/sc2/src/sc2code/libs/file.h @@ -0,0 +1,50 @@ +/* + * This program 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. + * + * This program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +// Contains file handling code + +#ifndef _FILE_H + +/* Make sure we have PATH_MAX */ +#ifdef WIN32 +# include +# define PATH_MAX _MAX_PATH +#else + /* PATH_MAX is per POSIX defined in */ +# include +#endif +#ifdef WIN32 +# include +# define access _access +# define F_OK 0 +# define W_OK 2 +# define R_OK 4 +# define mkdir _mkdir +# define rmdir _rmdir +#else +# include +#endif + +void initTempDir (void); +void unInitTempDir (void); +char *tempFilePath (const char *filename); +int mkdirhier (const char *path); +const char *getHomeDir (void); +int createDirectory(const char *dir, int mode); +int expandPath(char *dest, size_t len, const char *src); + +#endif /* _FILE_H */ + diff --git a/sc2/src/sc2code/libs/file/Makeinfo b/sc2/src/sc2code/libs/file/Makeinfo new file mode 100644 index 000000000..4024c4b8e --- /dev/null +++ b/sc2/src/sc2code/libs/file/Makeinfo @@ -0,0 +1 @@ +uqm_CFILES="dirs.c temp.c" diff --git a/sc2/src/sc2code/libs/file/dirs.c b/sc2/src/sc2code/libs/file/dirs.c new file mode 100644 index 000000000..c2dccbc4c --- /dev/null +++ b/sc2/src/sc2code/libs/file/dirs.c @@ -0,0 +1,199 @@ +/* + * This program 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. + * + * This program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +// Contains code handling directories + +#include +#include +#include +#include +#include +#ifdef WIN32 +#include +#endif +#include "port.h" +#include "config.h" +#include "filintrn.h" + +int +createDirectory(const char *dir, int mode) { +#ifdef WIN32 + return mkdir (dir); +#else + return mkdir (dir, (mode_t) mode); +#endif +} + +// make all components of the path if they don't exist already +// returns 0 on success, -1 on failure. +// on failure, some parts may still have been created. +int +mkdirhier (const char *path) { + char *buf; // buffer + char *ptr; // end of the string in buf + const char *pathstart; // start of a component of path + const char *pathend; // first char past the end of a component of path + size_t len; + struct stat statbuf; + + len = strlen (path); + buf = alloca (len + 2); // one extra for possibly added '/' + + ptr = buf; + pathstart = path; + + if (*pathstart == '/') { + *ptr = '/'; + ptr++; + pathstart++; + } + + if (*pathstart == '\0') { + // path exists completely, nothing more to do + return 0; + } + + // walk through the path as long as the components exist + while (1) { + pathend = strchr (pathstart, '/'); + if (pathend == NULL) + pathend = path + len; + memcpy(ptr, pathstart, pathend - pathstart); + ptr += pathend - pathstart; + *ptr = '\0'; + + if (stat (buf, &statbuf) == -1) { + if (errno != ENOENT) { + fprintf (stderr, "Can't stat %s: %s\n", buf, + strerror (errno)); + return -1; + } + break; + } + + if (*pathend == '\0') + return 0; + + *ptr = '/'; + ptr++; + pathstart = pathend + 1; + while (*pathstart == '/') + pathstart++; + // pathstart is the next non-slash character + + if (*pathstart == '\0') + return 0; + } + + // create all components left + while (1) { + if (createDirectory (buf, 0777) == -1) { + fprintf (stderr, "Error: Can't create %s: %s\n", buf, + strerror (errno)); + return -1; + } + + if (*pathend == '\0') + break; + + *ptr = '/'; + ptr++; + pathstart = pathend + 1; + while (*pathstart == '/') + pathstart++; + // pathstart is the next non-slash character + + if (*pathstart == '\0') + break; + + pathend = strchr (pathstart, '/'); + if (pathend == NULL) + pathend = path + len; + + memcpy (ptr, pathstart, pathend - pathstart); + ptr += pathend - pathstart; + *ptr = '\0'; + } + return 0; +} + +// Get the user's home dir +// returns a pointer to a static buffer +const char * +getHomeDir(void) { + return getenv ("HOME"); +} + +int +expandPath(char *dest, size_t len, const char *src) { + size_t srclen; + + srclen = strlen (src); + if (src[0] == '~') + { + const char *home; + size_t homelen; + + if (src[1] != '/') + { + errno = EINVAL; + return -1; + } + + home = getHomeDir (); + if (home == NULL) + { + errno = ENOENT; + return -1; + } + homelen = strlen (home); + + if (homelen + srclen > len) + { + errno = ENAMETOOLONG; + return -1; + } + memcpy(dest, home, homelen); + dest += homelen; + src++; /* skip the ~ */ + } else { + if (strlen (src) >= len) + { + errno = ENAMETOOLONG; + return -1; + } + } + +#ifdef WIN32 + /* Replaces backslashes in path by slashes. */ + while (*src != '\0') + { + if (*src == '\\') + { + *(dest++) = '/'; + src++; + } + else + *(dest++) = *(src++); + } + *dest = '\0'; +#else + strcpy(dest, src); +#endif + return 0; +} + + diff --git a/sc2/src/sc2code/libs/file/filintrn.h b/sc2/src/sc2code/libs/file/filintrn.h new file mode 100644 index 000000000..4db0048a3 --- /dev/null +++ b/sc2/src/sc2code/libs/file/filintrn.h @@ -0,0 +1,27 @@ +/* + * This program 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. + * + * This program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +// Contains code handling temporary files and dirs + +#ifndef _FILEINTRN_H + +#include "../file.h" + +void CreateDirectory (const char *dir, int mode); +void RemoveTempDir (void); + +#endif /* _FILEINTRN_H */ + diff --git a/sc2/src/sc2code/libs/file/temp.c b/sc2/src/sc2code/libs/file/temp.c new file mode 100644 index 000000000..4d46f4546 --- /dev/null +++ b/sc2/src/sc2code/libs/file/temp.c @@ -0,0 +1,145 @@ +/* + * This program 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. + * + * This program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +// Contains code handling temporary files and dirs + +#include +#include +#include +#ifdef WIN32 +# include +#endif +#include +#include +#include "filintrn.h" +#include "timelib.h" +#include "port.h" +#include "libs/compiler.h" + +static char *tempDir; + +static void +removeTempDir (void) +{ + rmdir (tempDir); +} + +// Try if the null-terminated path 'dir' to a directory is valid +// as temp path. +// On success, 'buf' will be filled with the path, with a trailing /, +// null-terminated, and 0 is returned. +// On failure, EINVAL, ENAMETOOLONG, or one of the errors access() can return +// is returned, and the contents of buf is unspecified. +static int +tryTempDir (char *buf, size_t buflen, const char *dir) +{ + size_t len; + int haveSlash; + + if (dir == NULL) + return EINVAL; + + len = strlen (dir); + haveSlash = (dir[len - 1] == '/' +#ifdef WIN32 + || dir[len - 1] == '\\' +#endif + ); + if ((haveSlash ? len : len + 1) >= buflen) + return ENAMETOOLONG; + + strcpy (buf, dir); + if (!haveSlash) + { + buf[len] = '/'; + len++; + buf[len] = '\0'; + } + if (access (buf, R_OK | W_OK) == -1) + return errno; + return 0; +} + +static void +getTempDir (char *buf, size_t buflen) { + if (tryTempDir (buf, buflen, getenv("TMP")) && + tryTempDir (buf, buflen, getenv("TEMP")) && + tryTempDir (buf, buflen, "/tmp/") && + tryTempDir (buf, buflen, "./")) + { + fprintf (stderr, "Fatal Error: Cannot find a suitable location " + "to store temporary files.\n"); + exit(EXIT_FAILURE); + } +} + +#define NUM_TEMP_RETRIES 16 + // Number of files to try to open before giving up. +void +initTempDir (void) { + size_t len; + DWORD num; + int i; + char *tempPtr; + // Pointer to the location in the tempDir string where the + // path to the temp dir ends and the dir starts. + + tempDir = malloc (PATH_MAX); + getTempDir (tempDir, PATH_MAX - 21); + // reserve 8 chars for dirname, 1 for slash, and 12 for filename + len = strlen(tempDir); + + num = ((DWORD) time (NULL)); +// num = GetTimeCounter () % 0xffffffff; + tempPtr = tempDir + len; + i = NUM_TEMP_RETRIES; + while (i--) + { + sprintf (tempPtr, "%08lx", num + i); + if (createDirectory (tempDir, 0700) == -1) + continue; + + // Success, we've got a temp dir. + tempDir = realloc (tempDir, len + 9); + atexit (removeTempDir); + return; + } + + // Failure, could not make a temporary directory. + fprintf(stderr, "Fatal error: Cannot get a name for a temporary " + "directory.\n"); + exit(EXIT_FAILURE); +} + +void +unInitTempDir (void) { + // nothing at the moment. + // the removing of the dir is handled via atexit +} + +// return the path to a file in the temp dir with the specified filename. +// returns a pointer to a static buffer. +char * +tempFilePath (const char *filename) { + static char file[PATH_MAX]; + + if (snprintf(file, PATH_MAX, "%s/%s", tempDir, filename) == -1) { + fprintf(stderr, "Path to temp file too long.\n"); + exit(EXIT_FAILURE); + } + return file; +} + diff --git a/sc2/src/sc2code/libs/resource/direct.c b/sc2/src/sc2code/libs/resource/direct.c index 9f4cdec29..b72830769 100644 --- a/sc2/src/sc2code/libs/resource/direct.c +++ b/sc2/src/sc2code/libs/resource/direct.c @@ -145,7 +145,7 @@ LoadDirEntryTable (PSTR pattern, PCOUNT pnum_entries) #include #include #include -#include +#include DIRENTRY_REF LoadDirEntryTable (PSTR pattern, PCOUNT pnum_entries) @@ -154,10 +154,10 @@ LoadDirEntryTable (PSTR pattern, PCOUNT pnum_entries) STRING_TABLE StringTable; STRING_TABLEPTR lpST; PDWORD lpLastOffs; - PSTR slash; // Pointer inside pattern to the last / - SBYTE path[MAXPATHLEN + 1]; // buffer for a filename with path - PSTR file; // Pointer inside path to the filename - size_t pathlen; // length of path, excluding last / and filename + PSTR slash; // Pointer inside pattern to the last / + SBYTE path[PATH_MAX]; // buffer for a filename with path + PSTR file; // Pointer inside path to the filename + size_t pathlen; // length of path, excluding last / and filename slash = (PSTR) strrchr ((const char *) pattern, '/'); if (slash == NULL) diff --git a/sc2/src/sc2code/load.c b/sc2/src/sc2code/load.c index 44cded531..20329f3b5 100644 --- a/sc2/src/sc2code/load.c +++ b/sc2/src/sc2code/load.c @@ -19,6 +19,8 @@ #include "starcon.h" #include "declib.h" #include "libs/tasklib.h" +#include "options.h" +#include "file.h" ACTIVITY NextActivity; @@ -85,10 +87,10 @@ BOOLEAN LoadGame (COUNT which_game, SUMMARY_DESC *summary_desc) { FILE *in_fp; - char buf[256]; + char buf[256], file[PATH_MAX]; - sprintf (buf, "starcon2.%02u", which_game); - in_fp = OpenResFile (buf, "rb"); + sprintf (file, "%sstarcon2.%02u", saveDir, which_game); + in_fp = OpenResFile (file, "rb"); if (in_fp) { FILE *fp; @@ -221,7 +223,7 @@ LoadGame (COUNT which_game, SUMMARY_DESC *summary_desc) } } - fp = OpenResFile (STARINFO_FILE, "wb"); + fp = OpenResFile (tempFilePath (STARINFO_FILE), "wb"); if (fp) { DWORD flen; @@ -240,7 +242,7 @@ LoadGame (COUNT which_game, SUMMARY_DESC *summary_desc) CloseResFile (fp); } - fp = OpenResFile (DEFGRPINFO_FILE, "wb"); + fp = OpenResFile (tempFilePath (DEFGRPINFO_FILE), "wb"); if (fp) { DWORD flen; @@ -259,7 +261,7 @@ LoadGame (COUNT which_game, SUMMARY_DESC *summary_desc) CloseResFile (fp); } - fp = OpenResFile (RANDGRPINFO_FILE, "wb"); + fp = OpenResFile (tempFilePath (RANDGRPINFO_FILE), "wb"); if (fp) { DWORD flen; diff --git a/sc2/src/sc2code/melee.c b/sc2/src/sc2code/melee.c index ceee1d1c2..588cbb6f7 100644 --- a/sc2/src/sc2code/melee.c +++ b/sc2/src/sc2code/melee.c @@ -19,6 +19,8 @@ #include #include "starcon.h" #include "melee.h" +#include "options.h" +#include "file.h" //Added by Chris @@ -1014,11 +1016,18 @@ static void LoadTeamList (PMELEE_STATE pMS, UNICODE *pbuf) { COUNT num_entries; + char dir[PATH_MAX]; + char file[PATH_MAX]; + char *loc_buf; + sprintf (dir, "%s*.mle", meleeDir); + strcpy (file, meleeDir); + loc_buf = file + strlen (file); + GetNewList: DestroyDirEntryTable (ReleaseDirEntryTable (pMS->TeamDE)); pMS->TeamDE = CaptureDirEntryTable ( - LoadDirEntryTable ("*.mle", &num_entries) + LoadDirEntryTable (dir, &num_entries) ); pMS->CurIndex = 0; @@ -1027,10 +1036,9 @@ GetNewList: int status; FILE *load_fp; TEAM_IMAGE TI; - UNICODE loc_buf[60]; GetDirEntryContents (pMS->TeamDE, (STRINGPTR)loc_buf, FALSE); - if ((load_fp = OpenResFile (loc_buf, "rb")) == 0) + if ((load_fp = OpenResFile (file, "rb")) == 0) status = -1; else { @@ -1042,7 +1050,7 @@ GetNewList: } if (status == -1) { - DeleteResFile (loc_buf); + DeleteResFile (file); goto GetNewList; } @@ -1060,15 +1068,19 @@ static BOOLEAN DoSaveTeam (PMELEE_STATE pMS) { STAMP MsgStamp; - UNICODE buf[60]; + char buf[PATH_MAX]; + char *file; FILE *save_fp; CONTEXT OldContext; + strcpy(buf, meleeDir); + file = buf + strlen (buf); + sprintf (file, "%s.mle", pMS->TeamImage[pMS->side].TeamName); + RetrySave: SetSemaphore (GraphicsSem); OldContext = SetContext (ScreenContext); ConfirmSaveLoad (&MsgStamp); - wsprintf (buf, "%s.mle", pMS->TeamImage[pMS->side].TeamName); save_fp = OpenResFile (buf, "wb"); if (save_fp) { @@ -1094,7 +1106,7 @@ RetrySave: goto RetrySave; } - LoadTeamList (pMS, buf); + LoadTeamList (pMS, file); if (save_fp) { diff --git a/sc2/src/sc2code/save.c b/sc2/src/sc2code/save.c index 510064b51..69a180f66 100644 --- a/sc2/src/sc2code/save.c +++ b/sc2/src/sc2code/save.c @@ -18,11 +18,14 @@ #include "starcon.h" #include "declib.h" +#include "file.h" +#include "options.h" void FreeSC2Data (void); BOOLEAN LoadSC2Data (void); + static void SaveShipQueue (DECODE_REF fh, PQUEUE pQueue) { @@ -306,7 +309,7 @@ RetrySave: FRAME frame; POINT pt; STAR_DESC SD; - char buf[256]; + char buf[256], file[PATH_MAX]; extern void SaveFlagshipState (void); success = TRUE; @@ -378,7 +381,7 @@ RetrySave: } } - fp = OpenResFile (STARINFO_FILE, "rb"); + fp = OpenResFile (tempFilePath (STARINFO_FILE), "rb"); if (fp) { flen = LengthResFile (fp); @@ -396,7 +399,7 @@ RetrySave: CloseResFile (fp); } - fp = OpenResFile (DEFGRPINFO_FILE, "rb"); + fp = OpenResFile (tempFilePath (DEFGRPINFO_FILE), "rb"); if (fp) { flen = LengthResFile (fp); @@ -414,7 +417,7 @@ RetrySave: CloseResFile (fp); } - fp = OpenResFile (RANDGRPINFO_FILE, "rb"); + fp = OpenResFile (tempFilePath (RANDGRPINFO_FILE), "rb"); if (fp) { flen = LengthResFile (fp); @@ -436,9 +439,9 @@ RetrySave: flen = cclose (fh); - sprintf (buf, "starcon2.%02u", which_game); -// fprintf (stderr, "'%s' is %lu bytes long\n", buf, flen + sizeof (*summary_desc)); - if (flen && (out_fp = (PVOID)OpenResFile (buf, "wb"))) + sprintf (file, "%sstarcon2.%02u", saveDir, which_game); +// fprintf (stderr, "'%s' is %lu bytes long\n", file, flen + sizeof (*summary_desc)); + if (flen && (out_fp = (PVOID)OpenResFile (file, "wb"))) { PrepareSummary (summary_desc); @@ -457,7 +460,7 @@ RetrySave: success = FALSE; if (!success) - DeleteResFile (buf); + DeleteResFile (file); } mem_unlock (h); diff --git a/sc2/src/sc2code/state.c b/sc2/src/sc2code/state.c index 310f06aab..f550c090b 100644 --- a/sc2/src/sc2code/state.c +++ b/sc2/src/sc2code/state.c @@ -20,13 +20,14 @@ #ifdef HAVE_UNISTD_H #include #endif +#include "file.h" void InitPlanetInfo (void) { PVOID fp; - fp = OpenResFile (STARINFO_FILE, "wb"); + fp = OpenResFile (tempFilePath (STARINFO_FILE), "wb"); if (fp) { DWORD offset; @@ -48,7 +49,7 @@ InitPlanetInfo (void) void UninitPlanetInfo (void) { - unlink (STARINFO_FILE); + unlink (tempFilePath (STARINFO_FILE)); } void @@ -59,7 +60,7 @@ GetPlanetInfo (void) pSolarSysState->SysInfo.PlanetInfo.ScanRetrieveMask[BIOLOGICAL_SCAN] = pSolarSysState->SysInfo.PlanetInfo.ScanRetrieveMask[MINERAL_SCAN] = pSolarSysState->SysInfo.PlanetInfo.ScanRetrieveMask[ENERGY_SCAN] = 0; - fp = OpenResFile (STARINFO_FILE, "rb"); + fp = OpenResFile (tempFilePath (STARINFO_FILE), "rb"); if (fp) { COUNT star_index, planet_index, moon_index; @@ -106,7 +107,7 @@ PutPlanetInfo (void) { PVOID fp; - fp = OpenResFile (STARINFO_FILE, "r+b"); + fp = OpenResFile (tempFilePath (STARINFO_FILE), "r+b"); if (fp) { COUNT i; diff --git a/sc2/src/starcon2.c b/sc2/src/starcon2.c index a7f76a59c..39dce7253 100644 --- a/sc2/src/starcon2.c +++ b/sc2/src/starcon2.c @@ -16,11 +16,14 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef WIN32 -#include -#include "config.h" -#else -#include +#ifdef HAVE_UNISTD_H +# include +#endif +#ifdef WIN32 +# include +#endif +#ifdef HAVE_CONFIG_H +# include "config.h" #endif #ifdef HAVE_GETOPT_H @@ -33,16 +36,19 @@ #include "libs/sound/sound_common.h" #include "libs/input/input_common.h" #include "libs/tasklib.h" +#include "file.h" +#include "port.h" #include "options.h" + #if defined(GFXMODULE_SDL) || defined(SOUNDMODULE_SDL) # include // Including this is actually necessary on OSX. #endif -void +static void CDToContentDir (char *contentdir) { - char *testfile = "starcon.txt"; + const char *testfile = "starcon.txt"; if (!FileExists (testfile)) { @@ -50,7 +56,7 @@ CDToContentDir (char *contentdir) (chdir ("content") || !FileExists (testfile)) && (chdir ("../../content") || !FileExists (testfile))) { fprintf(stderr, "Fatal error: content not available, running from wrong dir?\n"); - exit(-1); + exit(EXIT_FAILURE); } } } @@ -64,7 +70,6 @@ main (int argc, char *argv[]) int width = 640, height = 480, bpp = 16; int vol; char contentdir[1000]; - char str[1000]; int option_index = 0, c; static struct option long_options[] = @@ -81,8 +86,8 @@ main (int argc, char *argv[]) {"musicvol", 1, NULL, 'M'}, {"sfxvol", 1, NULL, 'S'}, {"speechvol", 1, NULL, 'T'}, - {"3domusic", 0, NULL, 'e'}, - {"pcmusic", 0, NULL, 'm'}, + {"3domusic", 0, NULL, 'e'}, + {"pcmusic", 0, NULL, 'm'}, {"audioquality", 1, NULL, 'q'}, {"nosubtitles", 0, NULL, 'u'}, {0, 0, 0, 0} @@ -114,16 +119,15 @@ main (int argc, char *argv[]) gfxdriver = TFB_GFXDRIVER_SDL_OPENGL; break; case 'c': - sscanf(optarg, "%s", str); - if (!strcmp (str, "bilinear")) + if (!strcmp (optarg, "bilinear")) { gfxflags |= TFB_GFXFLAGS_SCALE_BILINEAR; } - else if (!strcmp (str, "sai")) + else if (!strcmp (optarg, "sai")) { gfxflags |= TFB_GFXFLAGS_SCALE_SAI; } - else if (!strcmp (str, "supersai")) + else if (!strcmp (optarg, "supersai")) { gfxflags |= TFB_GFXFLAGS_SCALE_SUPERSAI; } @@ -161,25 +165,24 @@ main (int argc, char *argv[]) vol = 100; speechVolumeScale = vol / 100.0f; break; - case 'e': - optWhichMusic = MUSIC_3DO; - break; - case 'm': - optWhichMusic = MUSIC_PC; - break; + case 'e': + optWhichMusic = MUSIC_3DO; + break; + case 'm': + optWhichMusic = MUSIC_PC; + break; case 'q': - sscanf(optarg, "%s", str); - if (!strcmp (str, "high")) + if (!strcmp (optarg, "high")) { soundflags &= ~(TFB_SOUNDFLAGS_MQAUDIO|TFB_SOUNDFLAGS_LQAUDIO); soundflags |= TFB_SOUNDFLAGS_HQAUDIO; } - else if (!strcmp (str, "medium")) + else if (!strcmp (optarg, "medium")) { soundflags &= ~(TFB_SOUNDFLAGS_HQAUDIO|TFB_SOUNDFLAGS_LQAUDIO); soundflags |= TFB_SOUNDFLAGS_MQAUDIO; } - else if (!strcmp (str, "low")) + else if (!strcmp (optarg, "low")) { soundflags &= ~(TFB_SOUNDFLAGS_HQAUDIO|TFB_SOUNDFLAGS_MQAUDIO); soundflags |= TFB_SOUNDFLAGS_LQAUDIO; @@ -204,8 +207,8 @@ main (int argc, char *argv[]) printf(" -M, --musicvol=VOLUME (0-100, default 100)\n"); printf(" -S, --sfxvol=VOLUME (0-100, default 100)\n"); printf(" -T, --speechvol=VOLUME (0-100, default 100)\n"); - printf(" -e, --3domusic (default)\n"); - printf(" -m, --pcmusic\n"); + printf(" -e, --3domusic (default)\n"); + printf(" -m, --pcmusic\n"); printf(" -q, --audioquality=QUALITY (high, medium or low, default medium)\n"); printf(" -u, --nosubtitles\n"); return 0; @@ -213,8 +216,12 @@ main (int argc, char *argv[]) } } + initTempDir(); CDToContentDir (contentdir); - + prepareConfigDir(); + prepareMeleeDir(); + prepareSaveDir(); + InitThreadSystem (); InitTimeSystem (); InitTaskSystem (); @@ -236,5 +243,7 @@ main (int argc, char *argv[]) TFB_FlushGraphics (); } - exit(0); + unInitTempDir(); + exit(EXIT_SUCCESS); } +