Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changed the macOS functionning so it is no more deprecated. #16

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
test-linux
test-win
test-macos
13 changes: 10 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
.PHONY: all check
.PHONY: all check clean

all: test-linux test-win
all: test-linux test-win test-macos

check: test-linux test-win
check: test-linux test-win test-macos
./test-linux
./test-win
./test-macos

clean:
rm -f test-linux test-win test-macos

test-linux: test-linux.c cfgpath.h
$(CC) -O0 -g -o $@ $<

test-win: test-win.c cfgpath.h shlobj.h
$(CC) -O0 -g -o $@ $< -I.

test-macos: test-macos.c cfgpath.h
$(CC) -O0 -g -o $@ $<
72 changes: 48 additions & 24 deletions cfgpath.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,28 @@
#define PATH_SEPARATOR_STRING "\\"
#elif defined(__APPLE__)
#define CFGPATH_MAC
#include <CoreServices/CoreServices.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/syslimits.h> /* PATH_MAX */
#include <sysdir.h> /* Apple API */
#include <glob.h> /* Utility stuff (replace the tilde) */
#define MAX_PATH PATH_MAX
#define PATH_SEPARATOR_CHAR '/'
#define PATH_SEPARATOR_STRING "/"
#else
#error cfgpath.h functions have not been implemented for your platform! Please send patches.
#endif

#ifdef __cplusplus
namespace cfgpath {
#endif

static inline void get_user_config_file(char *out, unsigned int maxlen, const char *appname);
static inline void get_user_config_folder(char *out, unsigned int maxlen, const char *appname);
static inline void get_user_data_folder(char *out, unsigned int maxlen, const char *appname);
static inline void get_user_cache_folder(char *out, unsigned int maxlen, const char *appname);

/** Get an absolute path to a single configuration file, specific to this user.
*
* This function is useful for programs that need only a single configuration
Expand All @@ -77,7 +90,7 @@
*
* Windows: C:\Users\jcitizen\AppData\Roaming\appname.ini
* Linux: /home/jcitizen/.config/appname.conf
* Mac: /Users/jcitizen/Library/Application Support/appname.conf
* Mac: /Users/jcitizen/Library/Application Support/appname/appname.conf
*
* @param out
* Buffer to write the path. On return will contain the path, or an empty
Expand Down Expand Up @@ -154,19 +167,15 @@ static inline void get_user_config_file(char *out, unsigned int maxlen, const ch
strcat(out, appname);
strcat(out, ".ini");
#elif defined(CFGPATH_MAC)
FSRef ref;
FSFindFolder(kUserDomain, kApplicationSupportFolderType, kCreateFolder, &ref);
char home[MAX_PATH];
FSRefMakePath(&ref, (UInt8 *)&home, MAX_PATH);
/* first +1 is "/", second is terminating null */
const char *ext = ".conf";
if (strlen(home) + 1 + strlen(appname) + strlen(ext) + 1 > maxlen) {
get_user_config_folder(out, maxlen, appname);
/* +1 is terminating null */
if (strlen(out) + strlen(appname) + strlen(ext) + 1 > maxlen) {
out[0] = 0;
return;
}

strcpy(out, home);
strcat(out, PATH_SEPARATOR_STRING);
// final copy
strcat(out, appname);
strcat(out, ext);
#endif
Expand Down Expand Up @@ -265,22 +274,33 @@ static inline void get_user_config_folder(char *out, unsigned int maxlen, const
mkdir(out);
strcat(out, "\\");
#elif defined(CFGPATH_MAC)
FSRef ref;
FSFindFolder(kUserDomain, kApplicationSupportFolderType, kCreateFolder, &ref);
char home[MAX_PATH];
FSRefMakePath(&ref, (UInt8 *)&home, MAX_PATH);
/* first +1 is "/", second is trailing "/", third is terminating null */
if (strlen(home) + 1 + strlen(appname) + 1 + 1 > maxlen) {
out[0] = 0;
const sysdir_search_path_enumeration_state state = sysdir_start_search_path_enumeration(
SYSDIR_DIRECTORY_APPLICATION_SUPPORT,
SYSDIR_DOMAIN_MASK_USER
);
if (!sysdir_get_next_search_path_enumeration(state, out)) {
out[0] = '\0';
return;
}
}

strcpy(out, home);
strcat(out, PATH_SEPARATOR_STRING);
strcat(out, appname);
/* Make the .config/appname folder if it doesn't already exist */
mkdir(out, 0755);
strcat(out, PATH_SEPARATOR_STRING);
// Remove the tilde
glob_t globbuf;
if (glob(out, GLOB_TILDE, NULL, &globbuf) == 0) {
/* first +1 is "/", second is trailing "/", third is terminating null */
if (strlen(globbuf.gl_pathv[0]) + 1 + strlen(appname) + 1 + 1 > maxlen) {
out[0] = '\0';
return;
}

// final copy
strcpy(out, globbuf.gl_pathv[0]);
strcat(out, PATH_SEPARATOR_STRING);
strcat(out, appname);
/* Make the config folder if it doesn't already exist */
mkdir(out, 0755);
strcat(out, PATH_SEPARATOR_STRING);
}
globfree(&globbuf);
#endif
}

Expand Down Expand Up @@ -472,4 +492,8 @@ static inline void get_user_cache_folder(char *out, unsigned int maxlen, const c
#endif
}

#ifdef __cplusplus
} // namespace cfgpath
#endif

#endif /* CFGPATH_H_ */
23 changes: 23 additions & 0 deletions test-macos.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#include "cfgpath.h"

#include <stdio.h>

int main() {
char* config_file = malloc(MAX_PATH * sizeof(char));
char* config_folder = malloc(MAX_PATH * sizeof(char));
char* data_folder = malloc(MAX_PATH * sizeof(char));
char* cache_folder = malloc(MAX_PATH * sizeof(char));
char* too_small = malloc(10 * sizeof(char));

get_user_config_file(config_file, MAX_PATH, "myapp");
get_user_config_folder(config_folder, MAX_PATH, "myapp");
get_user_data_folder(data_folder, MAX_PATH, "myapp");
get_user_cache_folder(cache_folder, MAX_PATH, "myapp");
get_user_config_folder(too_small, 10, "myapp");

printf("Config file: %s\n", strlen(config_file) ? config_file : "ERROR");
printf("Config folder: %s\n", strlen(config_folder) ? config_folder : "ERROR");
printf("Data folder: %s\n", strlen(data_folder) ? data_folder : "ERROR");
printf("Cache folder: %s\n", strlen(cache_folder) ? cache_folder : "ERROR");
printf("Should be error: %s\n", strlen(too_small) ? too_small : "ERROR");
}