#include "m_pd.h"
#include "s_stuff.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#ifdef HAVE_UNISTD_H
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#endif
#ifdef _WIN32
#include <windows.h>
#include <tchar.h>
#include <io.h>
#endif
#include "m_private_utils.h"
#ifdef __APPLE__
#include <CoreFoundation/CoreFoundation.h>
#endif
void sys_doflags(void);
static PERTHREAD char *sys_prefbuf;
static PERTHREAD int sys_prefbufsize;
static PERTHREAD FILE *sys_prefsavefp;
static void sys_initloadpreferences_file(const char *filename)
{ … }
static int sys_getpreference_file(const char *key, char *value, int size)
{ … }
static void sys_doneloadpreferences_file(void)
{ … }
static void sys_initsavepreferences_file(const char *filename)
{ … }
static void sys_putpreference_file(const char *key, const char *value)
{ … }
static void sys_donesavepreferences_file(void)
{ … }
#if defined(__APPLE__)
static PERTHREAD CFMutableDictionaryRef sys_prefdict = NULL;
static int preferences_getloadpath(char *dst, size_t size)
{
char embedded_prefs[MAXPDSTRING];
char user_prefs[MAXPDSTRING];
char *homedir = getenv("HOME");
struct stat statbuf;
pd_snprintf(embedded_prefs, MAXPDSTRING, "%s/../org.puredata.pd",
sys_libdir->s_name);
pd_snprintf(user_prefs, MAXPDSTRING,
"%s/Library/Preferences/org.puredata.pd.plist", homedir);
if (stat(user_prefs, &statbuf) == 0)
{
strncpy(dst, user_prefs, size);
return 0;
}
else
{
strncpy(dst, embedded_prefs, size);
return 1;
}
}
static void preferences_getsavepath(char *dst, size_t size)
{
char user_prefs[MAXPDSTRING];
pd_snprintf(user_prefs, MAXPDSTRING,
"%s/Library/Preferences/org.puredata.pd.plist", getenv("HOME"));
strncpy(dst, user_prefs, size);
}
static void sys_initloadpreferences(void)
{
char user_prefs[MAXPDSTRING];
CFStringRef path = NULL;
CFURLRef fileURL = NULL;
CFReadStreamRef stream = NULL;
CFErrorRef err = NULL;
CFPropertyListRef plist = NULL;
if (sys_prefbuf || sys_prefdict)
{
bug("sys_initloadpreferences");
return;
}
preferences_getloadpath(user_prefs, MAXPDSTRING);
path = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, user_prefs,
kCFStringEncodingUTF8, kCFAllocatorNull);
fileURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path,
kCFURLPOSIXPathStyle, false);
stream = CFReadStreamCreateWithFile(kCFAllocatorDefault, fileURL);
if (!stream || !CFReadStreamOpen(stream)) goto cleanup;
plist = CFPropertyListCreateWithStream(kCFAllocatorDefault, stream, 0,
kCFPropertyListImmutable, NULL, &err);
if (!plist) {
CFStringRef errString = CFErrorCopyDescription(err);
pd_error(0, "couldn't read preferences plist: %s",
CFStringGetCStringPtr(errString, kCFStringEncodingUTF8));
CFRelease(errString);
goto cleanup;
}
CFRetain(plist);
sys_prefdict = (CFMutableDictionaryRef)plist;
cleanup:
if (stream) {
if (CFReadStreamGetStatus(stream) == kCFStreamStatusOpen) {
CFReadStreamClose(stream);
}
CFRelease(stream);
}
if (fileURL) {CFRelease(fileURL);}
if (path) {CFRelease(path);}
if (err) {CFRelease(err);}
}
static void sys_doneloadpreferences(void)
{
if (sys_prefbuf)
sys_doneloadpreferences_file();
if (sys_prefdict)
{
CFRelease(sys_prefdict);
sys_prefdict = NULL;
}
}
static void sys_initsavepreferences(void)
{
if (sys_prefsavefp)
{
bug("sys_initsavepreferences");
return;
}
sys_prefdict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
}
static void sys_donesavepreferences(void)
{
char user_prefs[MAXPDSTRING];
CFStringRef path = NULL;
CFURLRef fileURL = NULL;
CFWriteStreamRef stream = NULL;
CFErrorRef err = NULL;
CFDataRef data = NULL;
if (sys_prefsavefp)
sys_donesavepreferences_file();
if (!sys_prefdict) return;
data = CFPropertyListCreateData(kCFAllocatorDefault,
(CFPropertyListRef)sys_prefdict,
kCFPropertyListBinaryFormat_v1_0, 0, &err);
if (!data)
{
CFStringRef errString = CFErrorCopyDescription(err);
pd_error(0, "couldn't write preferences plist: %s",
CFStringGetCStringPtr(errString, kCFStringEncodingUTF8));
CFRelease(errString);
goto cleanup;
}
preferences_getsavepath(user_prefs, MAXPDSTRING);
path = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, user_prefs,
kCFStringEncodingUTF8, kCFAllocatorNull);
fileURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path,
kCFURLPOSIXPathStyle, false);
stream = CFWriteStreamCreateWithFile(kCFAllocatorDefault, fileURL);
if (!stream || !CFWriteStreamOpen(stream)) goto cleanup;
if (CFWriteStreamWrite(stream, CFDataGetBytePtr(data),
CFDataGetLength(data)) < 0) {
pd_error(0, "couldn't write preferences plist");
goto cleanup;
}
cleanup:
if (sys_prefdict)
{
CFRelease(sys_prefdict);
sys_prefdict = NULL;
}
if (data) {CFRelease(data);}
if (stream) {
if(CFWriteStreamGetStatus(stream) == kCFStreamStatusOpen) {
CFWriteStreamClose(stream);
}
CFRelease(stream);
}
if (fileURL) {CFRelease(fileURL);}
if (path) {CFRelease(path);}
if (err) {CFRelease(err);}
}
static int sys_getpreference(const char *key, char *value, int size)
{
if (sys_prefbuf)
return (sys_getpreference_file(key, value, size));
if (sys_prefdict) {
CFStringRef k = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault,
key, kCFStringEncodingUTF8, kCFAllocatorNull);
void *v = NULL;
int ret = 0;
if (CFDictionaryGetValueIfPresent(sys_prefdict, k,
(const void **)&v)) {
ret = CFStringGetCString((CFStringRef)v, value, size,
kCFStringEncodingUTF8);
#if 0
if (ret) fprintf(stderr, "plist read %s = %s\n", key, value);
#endif
if (v) CFRelease(v);
}
CFRelease(k);
return (ret);
}
else {
char cmdbuf[256];
int nread = 0, nleft = size;
char path[MAXPDSTRING];
int embedded = preferences_getloadpath(path, MAXPDSTRING);
if (embedded)
pd_snprintf(cmdbuf, 256, "defaults read %s %s 2> /dev/null\n",
path, key);
else
pd_snprintf(cmdbuf, 256, "defaults read org.puredata.pd %s 2> /dev/null\n",
key);
FILE *fp = popen(cmdbuf, "r");
while (nread < size)
{
int newread = fread(value+nread, 1, size-nread, fp);
if (newread <= 0)
break;
nread += newread;
}
pclose(fp);
if (nread < 1)
return (0);
if (nread >= size)
nread = size-1;
value[nread] = 0;
if (value[nread-1] == '\n')
value[nread-1] = 0;
return (1);
}
}
static void sys_putpreference(const char *key, const char *value)
{
if (sys_prefsavefp)
{
sys_putpreference_file(key, value);
return;
}
if (sys_prefdict) {
CFStringRef k = CFStringCreateWithCString(kCFAllocatorDefault, key,
kCFStringEncodingUTF8);
CFStringRef v = CFStringCreateWithCString(kCFAllocatorDefault, value,
kCFStringEncodingUTF8);
CFDictionarySetValue((CFMutableDictionaryRef)sys_prefdict, k, v);
CFRelease(k);
CFRelease(v);
#if 0
fprintf(stderr, "plist write %s = %s\n", key, value);
#endif
}
else {
char cmdbuf[MAXPDSTRING];
pd_snprintf(cmdbuf, MAXPDSTRING,
"defaults write org.puredata.pd %s \"%s\" 2> /dev/null\n", key, value);
system(cmdbuf);
}
}
#elif defined(_WIN32)
static void sys_initloadpreferences(void)
{
if (sys_prefbuf)
bug("sys_initloadpreferences");
}
static void sys_doneloadpreferences(void)
{
if (sys_prefbuf)
sys_doneloadpreferences_file();
}
static int sys_deletepreference(const char *key);
static void sys_initsavepreferences(void)
{
if (sys_prefsavefp)
bug("sys_initsavepreferences");
else
{
int i, j;
char buf[MAXPDSTRING], devname[MAXPDSTRING];
const char *key[4] = { "audioin", "audioout", "midiin", "midiout" };
int maxnum[4] = { MAXAUDIOINDEV, MAXAUDIOOUTDEV, MAXMIDIINDEV, MAXMIDIOUTDEV };
for (i = 0; i < 4; i++)
{
for (j = 0; j < maxnum[i]; j++)
{
pd_snprintf(buf, sizeof(buf), "%sdev%d", key[i], j + 1);
pd_snprintf(devname, sizeof(devname), "%sdevname%d", key[i], j + 1);
if (!sys_deletepreference(buf) || !sys_deletepreference(devname))
break;
}
}
for (i = 0; ; i++)
{
pd_snprintf(buf, sizeof(buf), "path%d", i + 1);
if (!sys_deletepreference(buf))
break;
}
}
}
static void sys_donesavepreferences(void)
{
if (sys_prefsavefp)
sys_donesavepreferences_file();
}
static int sys_getpreference(const char *key, char *value, int size)
{
if (sys_prefbuf)
return (sys_getpreference_file(key, value, size));
else
{
HKEY hkey;
DWORD bigsize = size;
LONG err = RegOpenKeyEx(HKEY_CURRENT_USER,
"Software\\Pure-Data", 0, KEY_QUERY_VALUE, &hkey);
if (err != ERROR_SUCCESS)
return (0);
err = RegQueryValueEx(hkey, key, 0, 0, (LPBYTE)value, &bigsize);
if (err != ERROR_SUCCESS)
{
RegCloseKey(hkey);
return (0);
}
RegCloseKey(hkey);
return (1);
}
}
static void sys_putpreference(const char *key, const char *value)
{
if (sys_prefsavefp)
sys_putpreference_file(key, value);
else
{
HKEY hkey;
LONG err = RegCreateKeyEx(HKEY_CURRENT_USER,
"Software\\Pure-Data", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE,
NULL, &hkey, NULL);
if (err != ERROR_SUCCESS)
{
pd_error(0, "unable to create registry entry: %s\n", key);
return;
}
err = RegSetValueEx(hkey, key, 0, REG_EXPAND_SZ, (const LPBYTE)value, strlen(value)+1);
if (err != ERROR_SUCCESS)
pd_error(0, "unable to set registry entry: %s\n", key);
RegCloseKey(hkey);
}
}
static int sys_deletepreference(const char *key)
{
if (sys_prefsavefp)
{
bug("sys_deletepreference");
return 0;
}
else
{
HKEY hkey;
LONG err;
err = RegOpenKeyEx(HKEY_CURRENT_USER,
"Software\\Pure-Data", 0, KEY_SET_VALUE, &hkey);
if (err != ERROR_SUCCESS)
return 0;
err = RegDeleteValue(hkey, key);
if (err == ERROR_SUCCESS)
{
RegCloseKey(hkey);
return 1;
} else if (err != ERROR_FILE_NOT_FOUND)
pd_error(0, "unable to delete registry entry: %s\n", key);
RegCloseKey(hkey);
return 0;
}
}
#else
static void sys_initloadpreferences(void)
{ … }
static int sys_getpreference(const char *key, char *value, int size)
{ … }
static void sys_doneloadpreferences(void)
{ … }
static void sys_initsavepreferences(void)
{ … }
static void sys_putpreference(const char *key, const char *value)
{ … }
static void sys_donesavepreferences(void)
{ … }
#endif
void sys_loadpreferences(const char *filename, int startingup)
{ … }
void sys_savepreferences(const char *filename)
{ … }
void glob_loadpreferences(t_pd *dummy, t_symbol *filesym)
{ … }
void glob_savepreferences(t_pd *dummy, t_symbol *filesym)
{ … }
void glob_forgetpreferences(t_pd *dummy)
{ … }
int sys_oktoloadfiles(int done)
{ … }