306 lines
7.5 KiB
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;
|
|
}
|
|
|
|
|