BeanCountersClassic/src/path.c

306 lines
7.5 KiB
C

/*
* path.c
* This file is part of Paddle Puffle
*
* Copyright (C) 2015 - Félix Arreola Rodríguez
*
* Paddle Puffle 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.
*
* Paddle Puffle 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 Paddle Puffle. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#ifdef MACOSX
// for search paths
#include "NSSystemDirectories.h"
#include <Carbon/Carbon.h>
#include <CoreFoundation/CoreFoundation.h>
#include <CoreServices/CoreServices.h>
#endif
#ifdef __MINGW32__
#include <windows.h>
#include <shellapi.h>
#endif
#include "path.h"
static char *systemdata_path;
static char *l10n_path;
static char *userdata_path;
//#ifdef __MINGW32__
//const char *PathSeparator = "\\"; // for path assembly
//#else
//const char *PathSeparator = "/"; // for path assembly
//#endif
//const char *PathSeparators = "/\\"; // for path splits
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE !FALSE
#endif
#ifndef MAX_PATH
# define MAX_PATH 2048
#endif
int folder_exists (const char *fname) {
struct stat s;
return (stat(fname, &s) == 0 && S_ISDIR(s.st_mode));
}
int file_exists (const char *fname) {
struct stat s;
return (stat(fname, &s) == 0 && S_ISREG(s.st_mode));
}
static int split_path (const char *path, char * dir_part, char * filename_part) {
int lslash, lnslash;
int g;
char *dup;
lslash = -1;
for (g = strlen (path) - 1; g >= 0; g--) {
if (path[g] == '/' || path[g] == '\\') {
lslash = g;
break;
}
}
if (
#ifdef __MINGW32__
lslash == 2 && path[1] == ':' && (path[0] >= 'A' && path[0] <= 'Z')
#else
lslash == 0
#endif
) {
return FALSE; // we cannot split the root directory apart
}
if (lslash == strlen (path) - 1) {
// trailing slash
dup = strdup (path);
dup[lslash] = 0;
g = split_path (dup, dir_part, filename_part);
free (dup);
return g;
}
if (lslash == -1) {
return FALSE;
}
for (g = lslash; g >= 0; g--) {
if (path[g] != '/' && path[g] != '\\') {
lnslash = g;
break;
}
}
if (dir_part) {
strncpy (dir_part, path, lnslash + 1);
dir_part[lnslash + 1] = 0;
}
if (filename_part) {
strcpy (filename_part, &path[lslash + 1]);
}
return TRUE;
}
int folder_create (const char *fname) {
char *parent_folder;
char *sub_folder;
int ok = TRUE;
if (folder_exists (fname)) return TRUE;
parent_folder = strdup (fname);
sub_folder = strdup (fname);
if (split_path (fname, parent_folder, sub_folder)) {
if (!folder_exists (parent_folder)) {
ok = folder_create(parent_folder);
}
}
if (ok) {
#ifdef __MINGW32__
ok = mkdir(fname) == 0;
#else
ok = mkdir(fname, 0775) == 0;
#endif
}
free (parent_folder);
free (sub_folder);
return ok;
}
#ifdef __MINGW32__
// should be ecl_system_windows.cc ?
static void ApplicationDataPath (char * buffer) {
typedef HRESULT (WINAPI *SHGETFOLDERPATH)( HWND, int, HANDLE, DWORD, LPTSTR );
# define CSIDL_FLAG_CREATE 0x8000
# define CSIDL_APPDATA 0x1A
# define SHGFP_TYPE_CURRENT 0
HINSTANCE shfolder_dll;
SHGETFOLDERPATH SHGetFolderPath ;
/* load the shfolder.dll to retreive SHGetFolderPath */
if ((shfolder_dll = LoadLibrary("shfolder.dll")) != NULL) {
SHGetFolderPath = (SHGETFOLDERPATH)GetProcAddress(shfolder_dll, "SHGetFolderPathA");
if (SHGetFolderPath != NULL) {
TCHAR szPath[MAX_PATH] = "";
/* get the "Application Data" folder for the current user */
if (S_OK == SHGetFolderPath (NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, szPath)) {
strcpy (buffer, szPath);
}
} else {
buffer[0] = '\0';
}
FreeLibrary (shfolder_dll);
} else {
buffer[0] = '\0';
}
}
#endif
void initSystemPaths (const char *argv_0) {
char *progCallPath;
int progdirexists;
char *progdir;
char *pref_path;
#ifdef __MINGW32__
char winappdata_path[MAX_PATH];
ApplicationDataPath (winappdata_path);
#endif
progCallPath = strdup (argv_0);
#if MACOSX
CFBundleRef mainBundle = CFBundleGetMainBundle();
CFURLRef cfurlmain = CFBundleCopyExecutableURL(mainBundle);
CFStringRef cffileStr = CFURLCopyFileSystemPath(cfurlmain, kCFURLPOSIXPathStyle);
CFIndex cfmax = CFStringGetMaximumSizeOfFileSystemRepresentation(cffileStr);
char *localbuffer;
localbuffer = (char *) malloc (sizeof (char) * cfmax);
if (CFStringGetFileSystemRepresentation(cffileStr, localbuffer, cfmax)) {
free (progCallPath);
progCallPath = localbuffer; // error skips this and defaults to argv[0] which works for most purposes
}
CFRelease(mainBundle);
CFRelease(cfurlmain);
CFRelease(cffileStr);
#endif
progdir = strdup (progCallPath);
progdirexists = split_path (progCallPath, progdir, NULL);
/* Primero conseguir el system path */
#ifdef __MINGW32__
if (!progdirexists) {
systemdata_path = "./data/";
} else {
systemdata_path = (char *) malloc (strlen (progdir) + 50);
sprintf (systemdata_path, "%s/data/", progdir);
}
#elif MACOSX
// Mac OS X applications are self-contained bundles,
// i.e., directories like "Enigma.app". Resources are
// placed in those bundles under "Enigma.app/Contents/Resources",
// the main executable would be "Enigma.app/Contents/MacOS/enigma".
// Here, we get the executable name, clip off the last bit, chdir into it,
// then chdir to ../Resources. The original SDL implementation chdirs to
// "../../..", i.e. the directory the bundle is placed in. This breaks
// the self-containedness.
systemdata_path = (char *) malloc (sizeof (char) * (strlen (progdir) + 30));
sprintf (systemdata_path, "%s/../Resources/data/", progdir);
#else
/* Para Linux */
systemdata_path = GAMEDATA_DIR;
#endif
/* Ahora, conseguir el L10n */
l10n_path = LOCALEDIR;
#ifdef __MINGW32__
if (progdirexists) {
l10n_path = (char *) malloc (strlen (progdir) + strlen (l10n_path) + 10);
if (strncmp (LOCALEDIR, "/", 1) == 0 || strncmp (LOCALEDIR, "\\", 1) == 0) {
/* No necesita slash final */
sprintf (l10n_path, "%s%s", progdir, LOCALEDIR);
} else {
sprintf (l10n_path, "%s/%s", progdir, LOCALEDIR);
}
}
#elif MACOSX
l10n_path = (char *) malloc (sizeof (char) * (strlen (progdir) + 30));
sprintf (l10n_path, "%s/../Resources/locale", progdir);
#endif
/* Ahora conseguir el user path */
if (getenv ("HOME") != 0) {
pref_path = getenv ("HOME");
if (!folder_exists (pref_path)) {
if (!folder_create (pref_path)) {
fprintf (stderr, "Error Home directory does not exist.\n");
userdata_path = NULL;
}
}
#ifdef MACOSX
userdata_path = (char *) malloc (strlen (pref_path) + 40);
sprintf (userdata_path, "%s/Library/Application Support", pref_path);
#else
userdata_path = strdup (pref_path);
#endif
#ifdef __MINGW32__
} else if (winappdata_path[0] != 0) {
userdata_path = strdup (winappdata_path);
#endif
} else {
userdata_path = NULL;
}
/* Liberar las cadenas temporales */
free (progdir);
free (progCallPath);
}
char *get_systemdata_path (void) {
return systemdata_path;
}
char *get_l10n_path (void) {
return l10n_path;
}
char *get_userdata_path (void) {
return userdata_path;
}