17#include "SDL_stdinc.h"
36#include "glue_macos.h"
40#if HAS_UNIX && !__MACOSX__
49static char *xdgGetEnv(
const char *name )
51 char *env = SDL_getenv( name );
52 if ( ( env != NULL ) && ( env[0] !=
'\0' ) )
65static char *xdgEnvDup(
const char *name )
67 const char *env = xdgGetEnv( name );
82static char *xdgGetRelativeHome(
const char *envname,
83 const char *relativefallback )
85 char *relhome = xdgEnvDup( envname );
86 if ( ( relhome == NULL ) && ( errno != ENOMEM ) ) {
90 home = xdgGetEnv(
"HOME" );
93 homelen = strlen( home );
94 unsigned int fallbacklength;
95 fallbacklength = strlen( relativefallback );
96 relhome = malloc( homelen + fallbacklength + 1 );
97 if ( relhome == NULL )
99 memcpy( relhome, home, homelen );
100 memcpy( &relhome[homelen], relativefallback, fallbacklength + 1 );
101 relhome[homelen + fallbacklength] =
'\0';
117 if ( conf.datapath ) {
125 WARN( _(
"Cannot determine config path, using current directory." ) );
129 char *path = xdgGetRelativeHome(
"XDG_CONFIG_HOME",
"/.config" );
130 if ( path == NULL ) {
131 WARN( _(
"$XDG_CONFIG_HOME isn't set, using current directory." ) );
132 path = strdup(
"." );
138 char *path = SDL_getenv(
"APPDATA" );
139 if ( path == NULL ) {
140 WARN( _(
"%%APPDATA%% isn't set, using current directory." ) );
144#elif SDL_VERSION_ATLEAST( 3, 0, 0 )
145 char *prefpath = SDL_GetPrefPath(
"Naev DevTeam",
"Naev" );
147 SDL_free( prefpath );
149#error "Feature needs implementation on this Operating System for Naev to work."
166 if ( conf.datapath ) {
173 WARN( _(
"Cannot determine cache path, using current directory." ) );
177 char *path = xdgGetRelativeHome(
"XDG_CACHE_HOME",
"/.cache" );
178 if ( path == NULL ) {
179 WARN( _(
"$XDG_CACHE_HOME isn't set, using current directory." ) );
180 path = strdup(
"." );
186 char *path = SDL_getenv(
"APPDATA" );
187 if ( path == NULL ) {
188 WARN( _(
"%%APPDATA%% isn't set, using current directory." ) );
192#elif SDL_VERSION_ATLEAST( 3, 0, 0 )
193 char *prefpath = SDL_GetPrefPath(
"Naev DevTeam",
"Naev" );
195 SDL_free( prefpath );
197#error "Feature needs implementation on this Operating System for Naev to work."
205#define MKDIR !CreateDirectory( opath, NULL )
206static int mkpath(
const char *path )
208#define MKDIR mkdir( opath, mode )
209static int mkpath(
const char *path, mode_t mode )
210#elif SDL_VERSION_ATLEAST( 3, 0, 0 )
211#define MKDIR SDL_CreateDirectory( opath )
213#error "Feature needs implementation on this Operating System for Naev to work."
224 strncpy( opath, path,
sizeof( opath ) - 1 );
225 opath[
sizeof( opath ) - 1] =
'\0';
226 len = strlen( opath );
235 for ( ; p >= opath; p-- ) {
250 for ( ; p[0] !=
'\0'; p++ ) {
254 if ( ret && ( errno != EEXIST ) )
287 if ( mkpath( path, S_IRWXU | S_IRWXG | S_IRWXO ) < 0 ) {
289 if ( mkpath( path ) < 0 ) {
290#elif SDL_VERSION_ATLEAST( 3, 0, 0 )
291 if ( SDL_CreateDirectory( path ) < 0 ) {
293#error "Feature needs implementation on this Operating System for Naev to work."
295 WARN( _(
"Dir '%s' does not exist and unable to create: %s" ), path,
336 if ( stat( path, &buf ) == 0 )
366 snprintf( backup,
sizeof( backup ),
"%s.backup", path );
392 f_in = fopen( file1,
"rb" );
393 f_out = fopen( file2,
"wb" );
394 if ( ( f_in == NULL ) || ( f_out == NULL ) ) {
395 WARN( _(
"Failure to copy '%s' to '%s': %s" ), file1, file2,
406 lr = fread( buf, 1,
sizeof( buf ), f_in );
407 if ( ferror( f_in ) )
415 lw = fwrite( buf, 1, lr, f_out );
416 if ( ferror( f_out ) || ( lr != lw ) )
427 WARN( _(
"Failure to copy '%s' to '%s': %s" ), file1, file2,
449 struct stat path_stat;
451 if ( path == NULL ) {
456 if ( stat( path, &path_stat ) ) {
457 WARN( _(
"Error occurred while opening '%s': %s" ), path,
463 if ( !S_ISREG( path_stat.st_mode ) ) {
464 WARN( _(
"Error occurred while opening '%s': It is not a regular file" ),
471 file = fopen( path,
"rb" );
472 if ( file == NULL ) {
473 WARN( _(
"Error occurred while opening '%s': %s" ), path,
480 if ( fseek( file, 0L, SEEK_END ) == -1 ) {
481 WARN( _(
"Error occurred while seeking '%s': %s" ), path,
488 if ( fseek( file, 0L, SEEK_SET ) == -1 ) {
489 WARN( _(
"Error occurred while seeking '%s': %s" ), path,
497 buf = malloc( len + 1 );
499 WARN( _(
"Out of Memory" ) );
509 pos = fread( &buf[n], 1, len - n, file );
511 WARN( _(
"Error occurred while reading '%s': %s" ), path,
541 f = fopen( path,
"a+b" );
543 WARN( _(
"Unable to touch file '%s': %s" ), path, strerror( errno ) );
569 file = fopen( path,
"wb" );
570 if ( file == NULL ) {
571 WARN( _(
"Error occurred while opening '%s': %s" ), path,
579 pos = fwrite( &data[n], 1, len - n, file );
581 WARN( _(
"Error occurred while writing '%s': %s" ), path,
590 if ( fclose( file ) == EOF ) {
591 WARN( _(
"Error occurred while closing '%s': %s" ), path,
610 else if (
c ==
'\\' )
616int _nfile_concatPaths(
char buf[
static 1],
int maxLength,
617 const char path[
static 1], ... )
625 bufEnd = buf + maxLength;
626 va_start( ap, path );
630 if ( section == NULL )
631 WARN( _(
"First argument to nfile_concatPaths was NULL. This is probably "
637 if ( section == NULL )
640 if ( bufPos > buf ) {
642 if ( bufPos[-1] !=
'/' ) {
647 if ( *section ==
'/' )
652 bufPos = memccpy( bufPos, section,
'\0', bufEnd - bufPos );
653 if ( bufPos == NULL )
657 section = va_arg( ap,
char * );
664 if ( section != NULL )
679 char *saveptr = NULL;
680 size_t n = strlen( path );
681 int absolute = ( path[0] ==
'/' );
682 char *token = SDL_strtokr( path,
"/", &saveptr );
684 while ( token != NULL ) {
686 if ( ( strcmp( token,
"" ) == 0 ) || ( strcmp( token,
"." ) == 0 ) ) {
687 token = SDL_strtokr( NULL,
"/", &saveptr );
692 if ( strcmp( token,
".." ) == 0 ) {
695 free( dirnames[dn - 1] );
696 array_erase( &dirnames, &dirnames[dn - 1], &dirnames[dn] );
703 token = SDL_strtokr( NULL,
"/", &saveptr );
715 for (
int i = 0; i <
array_size( dirnames ); i++ ) {
716 char *ds = dirnames[i];
717 if ( ( absolute || ( s > 0 ) ) && ( s < n ) )
719 for (
size_t j = 0; j < strlen( ds ); j++ )
729#if !SDL_VERSION_ATLEAST( 3, 0, 0 )
731void SDL_ShowOpenFileDialog( SDL_DialogFileCallback callback,
void *userdata,
734 const char *default_location, SDL_bool allow_many )
738 char *filelist[2] = { NULL, NULL };
741 for ( n = 0; filters[n].name != NULL; n++ )
744 nfdfilteritem_t *fitem = calloc( n,
sizeof( nfdfilteritem_t ) );
745 for (
int i = 0; i < n; i++ ) {
746 fitem[i].name = filters[i].name;
747 fitem[i].spec = filters[i].pattern;
754 (void)default_location;
755 nfdresult_t result = NFD_OpenDialog( &outPath, fitem, n, NULL );
757 nfdresult_t result = NFD_OpenDialog( &outPath, fitem, n, default_location );
761 filelist[0] = outPath;
762 callback( userdata, (
const char **)filelist, 0 );
763 NFD_FreePath( outPath );
767 callback( userdata, (
const char **)filelist, 0 );
771 SDL_SetError(
"%s", NFD_GetError() );
772 callback( userdata, NULL, -1 );
781void SDL_ShowOpenFolderDialog( SDL_DialogFileCallback callback,
void *userdata,
782 SDL_Window *window,
const char *default_location,
783 SDL_bool allow_many )
787 char *filelist[2] = { NULL, NULL };
793 (void)default_location;
794 nfdresult_t result = NFD_PickFolder( &outPath, NULL );
796 nfdresult_t result = NFD_PickFolder( &outPath, default_location );
800 filelist[0] = outPath;
801 callback( userdata, (
const char **)filelist, 0 );
802 NFD_FreePath( outPath );
806 callback( userdata, (
const char **)filelist, 0 );
810 SDL_SetError(
"%s", NFD_GetError() );
811 callback( userdata, NULL, -1 );
818void SDL_ShowSaveFileDialog( SDL_DialogFileCallback callback,
void *userdata,
821 const char *default_location )
824 char *filelist[2] = { NULL, NULL };
825 char *tmp, *bname, *dname;
828 for ( n = 0; filters[n].name != NULL; n++ )
831 nfdfilteritem_t *fitem = calloc( n,
sizeof( nfdfilteritem_t ) );
832 for (
int i = 0; i < n; i++ ) {
833 fitem[i].name = filters[i].name;
834 fitem[i].spec = filters[i].pattern;
838 tmp = strdup( default_location );
839 dname = strdup( dirname( tmp ) );
841 tmp = strdup( default_location );
842 bname = strdup( basename( tmp ) );
849 nfdresult_t result = NFD_SaveDialog( &outPath, fitem, n, NULL, bname );
851 nfdresult_t result = NFD_SaveDialog( &outPath, fitem, n, dname, bname );
855 filelist[0] = outPath;
856 callback( userdata, (
const char **)filelist, 0 );
857 NFD_FreePath( outPath );
861 callback( userdata, (
const char **)filelist, 0 );
865 SDL_SetError(
"%s", NFD_GetError() );
866 callback( userdata, NULL, -1 );
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
#define array_erase(ptr_array, first, last)
Erases elements in interval [first, last).
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
#define array_push_back(ptr_array, element)
Adds a new element at the end of the array.
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
int nfile_simplifyPath(char path[static 1])
Simplifies the path removing things like ".." or consecutive "/".
int nfile_copyIfExists(const char *file1, const char *file2)
Copy a file, if it exists.
const char * nfile_configPath(void)
Gets Naev's config path (for user preferences such as conf.lua)
static char naev_configPath[PATH_MAX]
int nfile_writeFile(const char *data, size_t len, const char *path)
Tries to write a file.
static char naev_cachePath[PATH_MAX]
char * nfile_readFile(size_t *filesize, const char *path)
Tries to read a file.
int nfile_dirMakeExist(const char *path)
Creates a directory if it doesn't exist.
int nfile_backupIfExists(const char *path)
Backup a file, if it exists.
const char * nfile_cachePath(void)
Gets Naev's cache path (for cached data such as generated textures)
int nfile_fileExists(const char *path)
Checks to see if a file exists.
int nfile_touch(const char *path)
Tries to create the file if it doesn't exist.
int nfile_isSeparator(uint32_t c)
Checks to see if a character is used to separate files in a path.
int nfile_dirExists(const char *path)
Checks to see if a directory exists.