#include <config.h>
#include <stdio.h>
#include <errno.h>
#include "lisp.h"
#include "process.h"
#ifdef MAC_OSX
#undef select
#endif
#include "systime.h"
#include "sysselect.h"
#include "blockinput.h"
#include "macterm.h"
#include "charset.h"
#include "coding.h"
#if !TARGET_API_MAC_CARBON
#include <Files.h>
#include <MacTypes.h>
#include <TextUtils.h>
#include <Folders.h>
#include <Resources.h>
#include <Aliases.h>
#include <Timer.h>
#include <OSA.h>
#include <AppleScript.h>
#include <Events.h>
#include <Processes.h>
#include <EPPC.h>
#include <MacLocales.h>
#include <Endian.h>
#endif
#include <utime.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <grp.h>
#include <sys/param.h>
#include <fcntl.h>
#if __MWERKS__
#include <unistd.h>
#endif
#include <CoreFoundation/CoreFoundation.h>
static int mac_system_script_code;
static Lisp_Object Vmac_system_locale;
static ComponentInstance as_scripting_component;
static OSAID as_script_context;
#if TARGET_API_MAC_CARBON
static int wakeup_from_rne_enabled_p = 0;
#define ENABLE_WAKEUP_FROM_RNE (wakeup_from_rne_enabled_p = 1)
#define DISABLE_WAKEUP_FROM_RNE (wakeup_from_rne_enabled_p = 0)
#else
#define ENABLE_WAKEUP_FROM_RNE 0
#define DISABLE_WAKEUP_FROM_RNE 0
#endif
#ifndef MAC_OSX
static OSErr posix_pathname_to_fsspec P_ ((const char *, FSSpec *));
static OSErr fsspec_to_posix_pathname P_ ((const FSSpec *, char *, int));
#endif
void
string_cat_and_replace (char *s1, const char *s2, int n, char a, char b)
{
int l1 = strlen (s1);
int l2 = strlen (s2);
char *p = s1 + l1;
int i;
strncat (s1, s2, n);
for (i = 0; i < l2; i++)
{
if (*p == a)
*p = b;
p++;
}
}
int
mac_to_posix_pathname (const char *mfn, char *ufn, int ufnbuflen)
{
const char *p, *q, *pe;
strcpy (ufn, "");
if (*mfn == '\0')
return 1;
p = strchr (mfn, ':');
if (p != 0 && p != mfn)
strcat (ufn, "/");
p = mfn;
if (*p == ':')
p++;
pe = mfn + strlen (mfn);
while (p < pe)
{
q = strchr (p, ':');
if (q)
{
if (q == p)
{
if (strlen (ufn) + 3 >= ufnbuflen)
return 0;
strcat (ufn, "../");
}
else
{
if (strlen (ufn) + (q - p) + 1 >= ufnbuflen)
return 0;
string_cat_and_replace (ufn, p, q - p, '/', ':');
strcat (ufn, "/");
}
p = q + 1;
}
else
{
if (strlen (ufn) + (pe - p) >= ufnbuflen)
return 0;
string_cat_and_replace (ufn, p, pe - p, '/', ':');
p = pe;
}
}
return 1;
}
extern char *get_temp_dir_name ();
int
posix_to_mac_pathname (const char *ufn, char *mfn, int mfnbuflen)
{
const char *p, *q, *pe;
char expanded_pathname[MAXPATHLEN+1];
strcpy (mfn, "");
if (*ufn == '\0')
return 1;
p = ufn;
if (*p == '/' && strchr (p+1, '/') == NULL && strcmp (p, "/.emacs") != 0)
{
if (strlen (p) + 1 > mfnbuflen)
return 0;
strcpy (mfn, p+1);
strcat (mfn, ":");
return 1;
}
if (strncmp (p, "~emacs/", 7) == 0)
{
struct passwd *pw = getpwnam ("emacs");
p += 7;
if (strlen (pw->pw_dir) + strlen (p) > MAXPATHLEN)
return 0;
strcpy (expanded_pathname, pw->pw_dir);
strcat (expanded_pathname, p);
p = expanded_pathname;
}
else if (strncmp (p, "/tmp/", 5) == 0)
{
char *t = get_temp_dir_name ();
p += 5;
if (strlen (t) + strlen (p) > MAXPATHLEN)
return 0;
strcpy (expanded_pathname, t);
strcat (expanded_pathname, p);
p = expanded_pathname;
}
else if (*p != '/')
strcat (mfn, ":");
if (*p == '/')
p++;
pe = p + strlen (p);
while (p < pe)
{
q = strchr (p, '/');
if (q)
{
if (q - p == 2 && *p == '.' && *(p+1) == '.')
{
if (strlen (mfn) + 1 >= mfnbuflen)
return 0;
strcat (mfn, ":");
}
else
{
if (strlen (mfn) + (q - p) + 1 >= mfnbuflen)
return 0;
string_cat_and_replace (mfn, p, q - p, ':', '/');
strcat (mfn, ":");
}
p = q + 1;
}
else
{
if (strlen (mfn) + (pe - p) >= mfnbuflen)
return 0;
string_cat_and_replace (mfn, p, pe - p, ':', '/');
p = pe;
}
}
return 1;
}
static Lisp_Object Qundecoded_file_name;
static struct {
AEKeyword keyword;
char *name;
Lisp_Object symbol;
} ae_attr_table [] =
{{keyTransactionIDAttr, "transaction-id"},
{keyReturnIDAttr, "return-id"},
{keyEventClassAttr, "event-class"},
{keyEventIDAttr, "event-id"},
{keyAddressAttr, "address"},
{keyOptionalKeywordAttr, "optional-keyword"},
{keyTimeoutAttr, "timeout"},
{keyInteractLevelAttr, "interact-level"},
{keyEventSourceAttr, "event-source"},
{keyOriginalAddressAttr, "original-address"},
{keyReplyRequestedAttr, "reply-requested"},
{KEY_EMACS_SUSPENSION_ID_ATTR, "emacs-suspension-id"}
};
static Lisp_Object
mac_aelist_to_lisp (desc_list)
const AEDescList *desc_list;
{
OSErr err;
long count;
Lisp_Object result, elem;
DescType desc_type;
Size size;
AEKeyword keyword;
AEDesc desc;
int attribute_p = 0;
err = AECountItems (desc_list, &count);
if (err != noErr)
return Qnil;
result = Qnil;
again:
while (count > 0)
{
if (attribute_p)
{
keyword = ae_attr_table[count - 1].keyword;
err = AESizeOfAttribute (desc_list, keyword, &desc_type, &size);
}
else
err = AESizeOfNthItem (desc_list, count, &desc_type, &size);
if (err == noErr)
switch (desc_type)
{
case typeAEList:
case typeAERecord:
case typeAppleEvent:
if (attribute_p)
err = AEGetAttributeDesc (desc_list, keyword, typeWildCard,
&desc);
else
err = AEGetNthDesc (desc_list, count, typeWildCard,
&keyword, &desc);
if (err != noErr)
break;
elem = mac_aelist_to_lisp (&desc);
AEDisposeDesc (&desc);
break;
default:
if (desc_type == typeNull)
elem = Qnil;
else
{
elem = make_uninit_string (size);
if (attribute_p)
err = AEGetAttributePtr (desc_list, keyword, typeWildCard,
&desc_type, SDATA (elem),
size, &size);
else
err = AEGetNthPtr (desc_list, count, typeWildCard, &keyword,
&desc_type, SDATA (elem), size, &size);
}
if (err != noErr)
break;
desc_type = EndianU32_NtoB (desc_type);
elem = Fcons (make_unibyte_string ((char *) &desc_type, 4), elem);
break;
}
if (err == noErr || desc_list->descriptorType == typeAEList)
{
if (err != noErr)
elem = Qnil;
else if (desc_list->descriptorType != typeAEList)
{
if (attribute_p)
elem = Fcons (ae_attr_table[count-1].symbol, elem);
else
{
keyword = EndianU32_NtoB (keyword);
elem = Fcons (make_unibyte_string ((char *) &keyword, 4),
elem);
}
}
result = Fcons (elem, result);
}
count--;
}
if (desc_list->descriptorType == typeAppleEvent && !attribute_p)
{
attribute_p = 1;
count = sizeof (ae_attr_table) / sizeof (ae_attr_table[0]);
goto again;
}
desc_type = EndianU32_NtoB (desc_list->descriptorType);
return Fcons (make_unibyte_string ((char *) &desc_type, 4), result);
}
Lisp_Object
mac_aedesc_to_lisp (desc)
const AEDesc *desc;
{
OSErr err = noErr;
DescType desc_type = desc->descriptorType;
Lisp_Object result;
switch (desc_type)
{
case typeNull:
result = Qnil;
break;
case typeAEList:
case typeAERecord:
case typeAppleEvent:
return mac_aelist_to_lisp (desc);
#if 0
{
long count;
Lisp_Object elem;
AEKeyword keyword;
AEDesc desc1;
err = AECountItems (desc, &count);
if (err != noErr)
break;
result = Qnil;
while (count > 0)
{
err = AEGetNthDesc (desc, count, typeWildCard, &keyword, &desc1);
if (err != noErr)
break;
elem = mac_aedesc_to_lisp (&desc1);
AEDisposeDesc (&desc1);
if (desc_type != typeAEList)
{
keyword = EndianU32_NtoB (keyword);
elem = Fcons (make_unibyte_string ((char *) &keyword, 4), elem);
}
result = Fcons (elem, result);
count--;
}
}
#endif
break;
default:
#if TARGET_API_MAC_CARBON
result = make_uninit_string (AEGetDescDataSize (desc));
err = AEGetDescData (desc, SDATA (result), SBYTES (result));
#else
result = make_uninit_string (GetHandleSize (desc->dataHandle));
memcpy (SDATA (result), *(desc->dataHandle), SBYTES (result));
#endif
break;
}
if (err != noErr)
return Qnil;
desc_type = EndianU32_NtoB (desc_type);
return Fcons (make_unibyte_string ((char *) &desc_type, 4), result);
}
OSErr
mac_ae_put_lisp (desc, keyword_or_index, obj)
AEDescList *desc;
UInt32 keyword_or_index;
Lisp_Object obj;
{
OSErr err;
if (!(desc->descriptorType == typeAppleEvent
|| desc->descriptorType == typeAERecord
|| desc->descriptorType == typeAEList))
return errAEWrongDataType;
if (CONSP (obj) && STRINGP (XCAR (obj)) && SBYTES (XCAR (obj)) == 4)
{
DescType desc_type1 = EndianU32_BtoN (*((UInt32 *) SDATA (XCAR (obj))));
Lisp_Object data = XCDR (obj), rest;
AEDesc desc1;
switch (desc_type1)
{
case typeNull:
case typeAppleEvent:
break;
case typeAEList:
case typeAERecord:
err = AECreateList (NULL, 0, desc_type1 == typeAERecord, &desc1);
if (err == noErr)
{
for (rest = data; CONSP (rest); rest = XCDR (rest))
{
UInt32 keyword_or_index1 = 0;
Lisp_Object elem = XCAR (rest);
if (desc_type1 == typeAERecord)
{
if (CONSP (elem) && STRINGP (XCAR (elem))
&& SBYTES (XCAR (elem)) == 4)
{
keyword_or_index1 =
EndianU32_BtoN (*((UInt32 *)
SDATA (XCAR (elem))));
elem = XCDR (elem);
}
else
continue;
}
err = mac_ae_put_lisp (&desc1, keyword_or_index1, elem);
if (err != noErr)
break;
}
if (err == noErr)
{
if (desc->descriptorType == typeAEList)
err = AEPutDesc (desc, keyword_or_index, &desc1);
else
err = AEPutParamDesc (desc, keyword_or_index, &desc1);
}
AEDisposeDesc (&desc1);
}
return err;
default:
if (!STRINGP (data))
break;
if (desc->descriptorType == typeAEList)
err = AEPutPtr (desc, keyword_or_index, desc_type1,
SDATA (data), SBYTES (data));
else
err = AEPutParamPtr (desc, keyword_or_index, desc_type1,
SDATA (data), SBYTES (data));
return err;
}
}
if (desc->descriptorType == typeAEList)
err = AEPutPtr (desc, keyword_or_index, typeNull, NULL, 0);
else
err = AEPutParamPtr (desc, keyword_or_index, typeNull, NULL, 0);
return err;
}
static pascal OSErr
mac_coerce_file_name_ptr (type_code, data_ptr, data_size,
to_type, handler_refcon, result)
DescType type_code;
const void *data_ptr;
Size data_size;
DescType to_type;
long handler_refcon;
AEDesc *result;
{
OSErr err;
if (type_code == typeNull)
err = errAECoercionFail;
else if (type_code == to_type || to_type == typeWildCard)
err = AECreateDesc (TYPE_FILE_NAME, data_ptr, data_size, result);
else if (type_code == TYPE_FILE_NAME)
{
#ifdef MAC_OSX
CFStringRef str;
CFURLRef url = NULL;
CFDataRef data = NULL;
str = CFStringCreateWithBytes (NULL, data_ptr, data_size,
kCFStringEncodingUTF8, false);
if (str)
{
url = CFURLCreateWithFileSystemPath (NULL, str,
kCFURLPOSIXPathStyle, false);
CFRelease (str);
}
if (url)
{
data = CFURLCreateData (NULL, url, kCFStringEncodingUTF8, true);
CFRelease (url);
}
if (data)
{
err = AECoercePtr (typeFileURL, CFDataGetBytePtr (data),
CFDataGetLength (data), to_type, result);
CFRelease (data);
}
else
err = memFullErr;
if (err != noErr)
{
FSRef fref;
char *buf;
buf = xmalloc (data_size + 1);
memcpy (buf, data_ptr, data_size);
buf[data_size] = '\0';
err = FSPathMakeRef (buf, &fref, NULL);
xfree (buf);
if (err == noErr)
err = AECoercePtr (typeFSRef, &fref, sizeof (FSRef),
to_type, result);
}
#else
FSSpec fs;
char *buf;
buf = xmalloc (data_size + 1);
memcpy (buf, data_ptr, data_size);
buf[data_size] = '\0';
err = posix_pathname_to_fsspec (buf, &fs);
xfree (buf);
if (err == noErr)
err = AECoercePtr (typeFSS, &fs, sizeof (FSSpec), to_type, result);
#endif
}
else if (to_type == TYPE_FILE_NAME)
{
#ifdef MAC_OSX
CFURLRef url = NULL;
CFStringRef str = NULL;
CFDataRef data = NULL;
if (type_code == typeFileURL)
url = CFURLCreateWithBytes (NULL, data_ptr, data_size,
kCFStringEncodingUTF8, NULL);
else
{
AEDesc desc;
Size size;
char *buf;
err = AECoercePtr (type_code, data_ptr, data_size,
typeFileURL, &desc);
if (err == noErr)
{
size = AEGetDescDataSize (&desc);
buf = xmalloc (size);
err = AEGetDescData (&desc, buf, size);
if (err == noErr)
url = CFURLCreateWithBytes (NULL, buf, size,
kCFStringEncodingUTF8, NULL);
xfree (buf);
AEDisposeDesc (&desc);
}
}
if (url)
{
str = CFURLCopyFileSystemPath (url, kCFURLPOSIXPathStyle);
CFRelease (url);
}
if (str)
{
data = CFStringCreateExternalRepresentation (NULL, str,
kCFStringEncodingUTF8,
'\0');
CFRelease (str);
}
if (data)
{
err = AECreateDesc (TYPE_FILE_NAME, CFDataGetBytePtr (data),
CFDataGetLength (data), result);
CFRelease (data);
}
if (err != noErr)
{
char file_name[MAXPATHLEN];
if (type_code == typeFSRef && data_size == sizeof (FSRef))
err = FSRefMakePath (data_ptr, file_name, sizeof (file_name));
else
{
AEDesc desc;
FSRef fref;
err = AECoercePtr (type_code, data_ptr, data_size,
typeFSRef, &desc);
if (err == noErr)
{
err = AEGetDescData (&desc, &fref, sizeof (FSRef));
AEDisposeDesc (&desc);
}
if (err == noErr)
err = FSRefMakePath (&fref, file_name, sizeof (file_name));
}
if (err == noErr)
err = AECreateDesc (TYPE_FILE_NAME, file_name,
strlen (file_name), result);
}
#else
char file_name[MAXPATHLEN];
if (type_code == typeFSS && data_size == sizeof (FSSpec))
err = fsspec_to_posix_pathname (data_ptr, file_name,
sizeof (file_name) - 1);
else
{
AEDesc desc;
FSSpec fs;
err = AECoercePtr (type_code, data_ptr, data_size, typeFSS, &desc);
if (err == noErr)
{
#if TARGET_API_MAC_CARBON
err = AEGetDescData (&desc, &fs, sizeof (FSSpec));
#else
fs = *(FSSpec *)(*(desc.dataHandle));
#endif
AEDisposeDesc (&desc);
}
if (err == noErr)
err = fsspec_to_posix_pathname (&fs, file_name,
sizeof (file_name) - 1);
}
if (err == noErr)
err = AECreateDesc (TYPE_FILE_NAME, file_name,
strlen (file_name), result);
#endif
}
else
abort ();
if (err != noErr)
return errAECoercionFail;
return noErr;
}
static pascal OSErr
mac_coerce_file_name_desc (from_desc, to_type, handler_refcon, result)
const AEDesc *from_desc;
DescType to_type;
long handler_refcon;
AEDesc *result;
{
OSErr err = noErr;
DescType from_type = from_desc->descriptorType;
if (from_type == typeNull)
err = errAECoercionFail;
else if (from_type == to_type || to_type == typeWildCard)
err = AEDuplicateDesc (from_desc, result);
else
{
char *data_ptr;
Size data_size;
#if TARGET_API_MAC_CARBON
data_size = AEGetDescDataSize (from_desc);
#else
data_size = GetHandleSize (from_desc->dataHandle);
#endif
data_ptr = xmalloc (data_size);
#if TARGET_API_MAC_CARBON
err = AEGetDescData (from_desc, data_ptr, data_size);
#else
memcpy (data_ptr, *(from_desc->dataHandle), data_size);
#endif
if (err == noErr)
err = mac_coerce_file_name_ptr (from_type, data_ptr,
data_size, to_type,
handler_refcon, result);
xfree (data_ptr);
}
if (err != noErr)
return errAECoercionFail;
return noErr;
}
OSErr
init_coercion_handler ()
{
OSErr err;
static AECoercePtrUPP coerce_file_name_ptrUPP = NULL;
static AECoerceDescUPP coerce_file_name_descUPP = NULL;
if (coerce_file_name_ptrUPP == NULL)
{
coerce_file_name_ptrUPP = NewAECoercePtrUPP (mac_coerce_file_name_ptr);
coerce_file_name_descUPP = NewAECoerceDescUPP (mac_coerce_file_name_desc);
}
err = AEInstallCoercionHandler (TYPE_FILE_NAME, typeWildCard,
(AECoercionHandlerUPP)
coerce_file_name_ptrUPP, 0, false, false);
if (err == noErr)
err = AEInstallCoercionHandler (typeWildCard, TYPE_FILE_NAME,
(AECoercionHandlerUPP)
coerce_file_name_ptrUPP, 0, false, false);
if (err == noErr)
err = AEInstallCoercionHandler (TYPE_FILE_NAME, typeWildCard,
coerce_file_name_descUPP, 0, true, false);
if (err == noErr)
err = AEInstallCoercionHandler (typeWildCard, TYPE_FILE_NAME,
coerce_file_name_descUPP, 0, true, false);
return err;
}
#if TARGET_API_MAC_CARBON
static OSErr
create_apple_event (class, id, result)
AEEventClass class;
AEEventID id;
AppleEvent *result;
{
OSErr err;
static const ProcessSerialNumber psn = {0, kCurrentProcess};
AEAddressDesc address_desc;
err = AECreateDesc (typeProcessSerialNumber, &psn,
sizeof (ProcessSerialNumber), &address_desc);
if (err == noErr)
{
err = AECreateAppleEvent (class, id,
&address_desc,
kAutoGenerateReturnID,
kAnyTransactionID, result);
AEDisposeDesc (&address_desc);
}
return err;
}
OSStatus
create_apple_event_from_event_ref (event, num_params, names, types, result)
EventRef event;
UInt32 num_params;
const EventParamName *names;
const EventParamType *types;
AppleEvent *result;
{
OSStatus err;
UInt32 i, size;
CFStringRef string;
CFDataRef data;
char *buf = NULL;
err = create_apple_event (0, 0, result);
if (err != noErr)
return err;
for (i = 0; i < num_params; i++)
switch (types[i])
{
#ifdef MAC_OSX
case typeCFStringRef:
err = GetEventParameter (event, names[i], typeCFStringRef, NULL,
sizeof (CFStringRef), NULL, &string);
if (err != noErr)
break;
data = CFStringCreateExternalRepresentation (NULL, string,
kCFStringEncodingUTF8,
'?');
if (data == NULL)
break;
AEPutParamPtr (result, names[i], typeUTF8Text,
CFDataGetBytePtr (data), CFDataGetLength (data));
CFRelease (data);
break;
#endif
default:
err = GetEventParameter (event, names[i], types[i], NULL,
0, &size, NULL);
if (err != noErr)
break;
buf = xrealloc (buf, size);
err = GetEventParameter (event, names[i], types[i], NULL,
size, NULL, buf);
if (err == noErr)
AEPutParamPtr (result, names[i], types[i], buf, size);
break;
}
if (buf)
xfree (buf);
return noErr;
}
OSErr
create_apple_event_from_drag_ref (drag, num_types, types, result)
DragRef drag;
UInt32 num_types;
const FlavorType *types;
AppleEvent *result;
{
OSErr err;
UInt16 num_items;
AppleEvent items;
long index;
char *buf = NULL;
err = CountDragItems (drag, &num_items);
if (err != noErr)
return err;
err = AECreateList (NULL, 0, false, &items);
if (err != noErr)
return err;
for (index = 1; index <= num_items; index++)
{
ItemReference item;
DescType desc_type = typeNull;
Size size;
err = GetDragItemReferenceNumber (drag, index, &item);
if (err == noErr)
{
int i;
for (i = 0; i < num_types; i++)
{
err = GetFlavorDataSize (drag, item, types[i], &size);
if (err == noErr)
{
buf = xrealloc (buf, size);
err = GetFlavorData (drag, item, types[i], buf, &size, 0);
}
if (err == noErr)
{
desc_type = types[i];
break;
}
}
}
err = AEPutPtr (&items, index, desc_type,
desc_type != typeNull ? buf : NULL,
desc_type != typeNull ? size : 0);
if (err != noErr)
break;
}
if (buf)
xfree (buf);
if (err == noErr)
{
err = create_apple_event (0, 0, result);
if (err == noErr)
err = AEPutParamDesc (result, keyDirectObject, &items);
if (err != noErr)
AEDisposeDesc (result);
}
AEDisposeDesc (&items);
return err;
}
#endif
#if TARGET_API_MAC_CARBON
static Lisp_Object Qstring, Qnumber, Qboolean, Qdate, Qdata;
static Lisp_Object Qarray, Qdictionary;
struct cfdict_context
{
Lisp_Object *result;
int with_tag, hash_bound;
};
CFStringRef
cfstring_create_with_utf8_cstring (c_str)
const char *c_str;
{
CFStringRef str;
str = CFStringCreateWithCString (NULL, c_str, kCFStringEncodingUTF8);
if (str == NULL)
str = CFStringCreateWithCString (NULL, c_str, kCFStringEncodingMacRoman);
return str;
}
CFStringRef
cfstring_create_with_string (s)
Lisp_Object s;
{
CFStringRef string = NULL;
if (STRING_MULTIBYTE (s))
{
char *p, *end = SDATA (s) + SBYTES (s);
for (p = SDATA (s); p < end; p++)
if (!isascii (*p))
{
s = ENCODE_UTF_8 (s);
break;
}
string = CFStringCreateWithBytes (NULL, SDATA (s), SBYTES (s),
kCFStringEncodingUTF8, false);
}
if (string == NULL)
string = CFStringCreateWithBytes (NULL, SDATA (s), SBYTES (s),
kCFStringEncodingMacRoman, false);
return string;
}
Lisp_Object
cfdata_to_lisp (data)
CFDataRef data;
{
CFIndex len = CFDataGetLength (data);
Lisp_Object result = make_uninit_string (len);
CFDataGetBytes (data, CFRangeMake (0, len), SDATA (result));
return result;
}
Lisp_Object
cfstring_to_lisp_nodecode (string)
CFStringRef string;
{
Lisp_Object result = Qnil;
const char *s = CFStringGetCStringPtr (string, kCFStringEncodingUTF8);
if (s)
result = make_unibyte_string (s, strlen (s));
else
{
CFDataRef data =
CFStringCreateExternalRepresentation (NULL, string,
kCFStringEncodingUTF8, '?');
if (data)
{
result = cfdata_to_lisp (data);
CFRelease (data);
}
}
return result;
}
Lisp_Object
cfstring_to_lisp (string)
CFStringRef string;
{
Lisp_Object result = cfstring_to_lisp_nodecode (string);
if (!NILP (result))
{
result = code_convert_string_norecord (result, Qutf_8, 0);
result = string_to_multibyte (result);
}
return result;
}
Lisp_Object
cfnumber_to_lisp (number)
CFNumberRef number;
{
Lisp_Object result = Qnil;
#if BITS_PER_EMACS_INT > 32
SInt64 int_val;
CFNumberType emacs_int_type = kCFNumberSInt64Type;
#else
SInt32 int_val;
CFNumberType emacs_int_type = kCFNumberSInt32Type;
#endif
double float_val;
if (CFNumberGetValue (number, emacs_int_type, &int_val)
&& !FIXNUM_OVERFLOW_P (int_val))
result = make_number (int_val);
else
if (CFNumberGetValue (number, kCFNumberDoubleType, &float_val))
result = make_float (float_val);
return result;
}
Lisp_Object
cfdate_to_lisp (date)
CFDateRef date;
{
static const CFGregorianDate epoch_gdate = {1970, 1, 1, 0, 0, 0.0};
static CFAbsoluteTime epoch = 0.0, sec;
int high, low;
if (epoch == 0.0)
epoch = CFGregorianDateGetAbsoluteTime (epoch_gdate, NULL);
sec = CFDateGetAbsoluteTime (date) - epoch;
high = sec / 65536.0;
low = sec - high * 65536.0;
return list3 (make_number (high), make_number (low), make_number (0));
}
Lisp_Object
cfboolean_to_lisp (boolean)
CFBooleanRef boolean;
{
return CFBooleanGetValue (boolean) ? Qt : Qnil;
}
Lisp_Object
cfobject_desc_to_lisp (object)
CFTypeRef object;
{
Lisp_Object result = Qnil;
CFStringRef desc = CFCopyDescription (object);
if (desc)
{
result = cfstring_to_lisp (desc);
CFRelease (desc);
}
return result;
}
static void
cfdictionary_add_to_list (key, value, context)
const void *key;
const void *value;
void *context;
{
struct cfdict_context *cxt = (struct cfdict_context *)context;
*cxt->result =
Fcons (Fcons (cfstring_to_lisp (key),
cfproperty_list_to_lisp (value, cxt->with_tag,
cxt->hash_bound)),
*cxt->result);
}
static void
cfdictionary_puthash (key, value, context)
const void *key;
const void *value;
void *context;
{
Lisp_Object lisp_key = cfstring_to_lisp (key);
struct cfdict_context *cxt = (struct cfdict_context *)context;
struct Lisp_Hash_Table *h = XHASH_TABLE (*(cxt->result));
unsigned hash_code;
hash_lookup (h, lisp_key, &hash_code);
hash_put (h, lisp_key,
cfproperty_list_to_lisp (value, cxt->with_tag, cxt->hash_bound),
hash_code);
}
Lisp_Object
cfproperty_list_to_lisp (plist, with_tag, hash_bound)
CFPropertyListRef plist;
int with_tag, hash_bound;
{
CFTypeID type_id = CFGetTypeID (plist);
Lisp_Object tag = Qnil, result = Qnil;
struct gcpro gcpro1, gcpro2;
GCPRO2 (tag, result);
if (type_id == CFStringGetTypeID ())
{
tag = Qstring;
result = cfstring_to_lisp (plist);
}
else if (type_id == CFNumberGetTypeID ())
{
tag = Qnumber;
result = cfnumber_to_lisp (plist);
}
else if (type_id == CFBooleanGetTypeID ())
{
tag = Qboolean;
result = cfboolean_to_lisp (plist);
}
else if (type_id == CFDateGetTypeID ())
{
tag = Qdate;
result = cfdate_to_lisp (plist);
}
else if (type_id == CFDataGetTypeID ())
{
tag = Qdata;
result = cfdata_to_lisp (plist);
}
else if (type_id == CFArrayGetTypeID ())
{
CFIndex index, count = CFArrayGetCount (plist);
tag = Qarray;
result = Fmake_vector (make_number (count), Qnil);
for (index = 0; index < count; index++)
XVECTOR (result)->contents[index] =
cfproperty_list_to_lisp (CFArrayGetValueAtIndex (plist, index),
with_tag, hash_bound);
}
else if (type_id == CFDictionaryGetTypeID ())
{
struct cfdict_context context;
CFIndex count = CFDictionaryGetCount (plist);
tag = Qdictionary;
context.result = &result;
context.with_tag = with_tag;
context.hash_bound = hash_bound;
if (hash_bound < 0 || count < hash_bound)
{
result = Qnil;
CFDictionaryApplyFunction (plist, cfdictionary_add_to_list,
&context);
}
else
{
result = make_hash_table (Qequal,
make_number (count),
make_float (DEFAULT_REHASH_SIZE),
make_float (DEFAULT_REHASH_THRESHOLD),
Qnil, Qnil, Qnil);
CFDictionaryApplyFunction (plist, cfdictionary_puthash,
&context);
}
}
else
abort ();
UNGCPRO;
if (with_tag)
result = Fcons (tag, result);
return result;
}
#endif
#define P (*p)
#define LOOSE_BINDING Qlambda
#define SINGLE_COMPONENT Qquote
static void
skip_white_space (p)
const char **p;
{
while (*P == ' ' || *P == '\t')
P++;
}
static int
parse_comment (p)
const char **p;
{
if (*P == '!')
{
P++;
while (*P)
if (*P++ == '\n')
break;
return 1;
}
else
return 0;
}
static int
parse_include_file (p)
const char **p;
{
if (*P == '#')
{
P++;
while (*P)
if (*P++ == '\n')
break;
return 1;
}
else
return 0;
}
static char
parse_binding (p)
const char **p;
{
if (*P == '.' || *P == '*')
{
char binding = *P++;
while (*P == '.' || *P == '*')
if (*P++ == '*')
binding = '*';
return binding;
}
else
return '\0';
}
static Lisp_Object
parse_component (p)
const char **p;
{
if (*P == '?')
{
P++;
return SINGLE_COMPONENT;
}
else if (isalnum (*P) || *P == '_' || *P == '-')
{
const char *start = P++;
while (isalnum (*P) || *P == '_' || *P == '-')
P++;
return make_unibyte_string (start, P - start);
}
else
return Qnil;
}
static Lisp_Object
parse_resource_name (p)
const char **p;
{
Lisp_Object result = Qnil, component;
char binding;
if (parse_binding (p) == '*')
result = Fcons (LOOSE_BINDING, result);
component = parse_component (p);
if (NILP (component))
return Qnil;
result = Fcons (component, result);
while ((binding = parse_binding (p)) != '\0')
{
if (binding == '*')
result = Fcons (LOOSE_BINDING, result);
component = parse_component (p);
if (NILP (component))
return Qnil;
else
result = Fcons (component, result);
}
if (EQ (component, SINGLE_COMPONENT))
return Qnil;
return Fnreverse (result);
}
static Lisp_Object
parse_value (p)
const char **p;
{
char *q, *buf;
Lisp_Object seq = Qnil, result;
int buf_len, total_len = 0, len, continue_p;
q = strchr (P, '\n');
buf_len = q ? q - P : strlen (P);
buf = xmalloc (buf_len);
while (1)
{
q = buf;
continue_p = 0;
while (*P)
{
if (*P == '\n')
{
P++;
break;
}
else if (*P == '\\')
{
P++;
if (*P == '\0')
break;
else if (*P == '\n')
{
P++;
continue_p = 1;
break;
}
else if (*P == 'n')
{
*q++ = '\n';
P++;
}
else if ('0' <= P[0] && P[0] <= '7'
&& '0' <= P[1] && P[1] <= '7'
&& '0' <= P[2] && P[2] <= '7')
{
*q++ = ((P[0] - '0') << 6) + ((P[1] - '0') << 3) + (P[2] - '0');
P += 3;
}
else
*q++ = *P++;
}
else
*q++ = *P++;
}
len = q - buf;
seq = Fcons (make_unibyte_string (buf, len), seq);
total_len += len;
if (continue_p)
{
q = strchr (P, '\n');
len = q ? q - P : strlen (P);
if (len > buf_len)
{
xfree (buf);
buf_len = len;
buf = xmalloc (buf_len);
}
}
else
break;
}
xfree (buf);
if (SBYTES (XCAR (seq)) == total_len)
return make_string (SDATA (XCAR (seq)), total_len);
else
{
buf = xmalloc (total_len);
q = buf + total_len;
for (; CONSP (seq); seq = XCDR (seq))
{
len = SBYTES (XCAR (seq));
q -= len;
memcpy (q, SDATA (XCAR (seq)), len);
}
result = make_string (buf, total_len);
xfree (buf);
return result;
}
}
static Lisp_Object
parse_resource_line (p)
const char **p;
{
Lisp_Object quarks, value;
if (parse_comment (p) || parse_include_file (p))
return Qnil;
skip_white_space (p);
quarks = parse_resource_name (p);
if (NILP (quarks))
goto cleanup;
skip_white_space (p);
if (*P != ':')
goto cleanup;
P++;
skip_white_space (p);
value = parse_value (p);
return Fcons (quarks, value);
cleanup:
parse_value (p);
return Qnil;
}
#undef P
#define HASHKEY_MAX_NID (make_number (0))
#define HASHKEY_QUERY_CACHE (make_number (-1))
static XrmDatabase
xrm_create_database ()
{
XrmDatabase database;
database = make_hash_table (Qequal, make_number (DEFAULT_HASH_SIZE),
make_float (DEFAULT_REHASH_SIZE),
make_float (DEFAULT_REHASH_THRESHOLD),
Qnil, Qnil, Qnil);
Fputhash (HASHKEY_MAX_NID, make_number (0), database);
Fputhash (HASHKEY_QUERY_CACHE, Qnil, database);
return database;
}
static void
xrm_q_put_resource (database, quarks, value)
XrmDatabase database;
Lisp_Object quarks, value;
{
struct Lisp_Hash_Table *h = XHASH_TABLE (database);
unsigned hash_code;
int max_nid, i;
Lisp_Object node_id, key;
max_nid = XINT (Fgethash (HASHKEY_MAX_NID, database, Qnil));
XSETINT (node_id, 0);
for (; CONSP (quarks); quarks = XCDR (quarks))
{
key = Fcons (node_id, XCAR (quarks));
i = hash_lookup (h, key, &hash_code);
if (i < 0)
{
max_nid++;
XSETINT (node_id, max_nid);
hash_put (h, key, node_id, hash_code);
}
else
node_id = HASH_VALUE (h, i);
}
Fputhash (node_id, value, database);
Fputhash (HASHKEY_MAX_NID, make_number (max_nid), database);
Fputhash (HASHKEY_QUERY_CACHE, Qnil, database);
}
void
xrm_merge_string_database (database, data)
XrmDatabase database;
const char *data;
{
Lisp_Object quarks_value;
while (*data)
{
quarks_value = parse_resource_line (&data);
if (!NILP (quarks_value))
xrm_q_put_resource (database,
XCAR (quarks_value), XCDR (quarks_value));
}
}
static Lisp_Object
xrm_q_get_resource_1 (database, node_id, quark_name, quark_class)
XrmDatabase database;
Lisp_Object node_id, quark_name, quark_class;
{
struct Lisp_Hash_Table *h = XHASH_TABLE (database);
Lisp_Object key, labels[3], value;
int i, k;
if (!CONSP (quark_name))
return Fgethash (node_id, database, Qnil);
labels[0] = XCAR (quark_name);
labels[1] = XCAR (quark_class);
labels[2] = SINGLE_COMPONENT;
key = Fcons (node_id, Qnil);
for (k = 0; k < sizeof (labels) / sizeof (*labels); k++)
{
XSETCDR (key, labels[k]);
i = hash_lookup (h, key, NULL);
if (i >= 0)
{
value = xrm_q_get_resource_1 (database, HASH_VALUE (h, i),
XCDR (quark_name), XCDR (quark_class));
if (!NILP (value))
return value;
}
}
XSETCDR (key, LOOSE_BINDING);
i = hash_lookup (h, key, NULL);
if (i >= 0)
{
value = xrm_q_get_resource_1 (database, HASH_VALUE (h, i),
quark_name, quark_class);
if (!NILP (value))
return value;
else
return xrm_q_get_resource_1 (database, node_id,
XCDR (quark_name), XCDR (quark_class));
}
else
return Qnil;
}
static Lisp_Object
xrm_q_get_resource (database, quark_name, quark_class)
XrmDatabase database;
Lisp_Object quark_name, quark_class;
{
return xrm_q_get_resource_1 (database, make_number (0),
quark_name, quark_class);
}
Lisp_Object
xrm_get_resource (database, name, class)
XrmDatabase database;
const char *name, *class;
{
Lisp_Object key, query_cache, quark_name, quark_class, tmp;
int i, nn, nc;
struct Lisp_Hash_Table *h;
unsigned hash_code;
nn = strlen (name);
nc = strlen (class);
key = make_uninit_string (nn + nc + 1);
strcpy (SDATA (key), name);
strncpy (SDATA (key) + nn + 1, class, nc);
query_cache = Fgethash (HASHKEY_QUERY_CACHE, database, Qnil);
if (NILP (query_cache))
{
query_cache = make_hash_table (Qequal, make_number (DEFAULT_HASH_SIZE),
make_float (DEFAULT_REHASH_SIZE),
make_float (DEFAULT_REHASH_THRESHOLD),
Qnil, Qnil, Qnil);
Fputhash (HASHKEY_QUERY_CACHE, query_cache, database);
}
h = XHASH_TABLE (query_cache);
i = hash_lookup (h, key, &hash_code);
if (i >= 0)
return HASH_VALUE (h, i);
quark_name = parse_resource_name (&name);
if (*name != '\0')
return Qnil;
for (tmp = quark_name, nn = 0; CONSP (tmp); tmp = XCDR (tmp), nn++)
if (!STRINGP (XCAR (tmp)))
return Qnil;
quark_class = parse_resource_name (&class);
if (*class != '\0')
return Qnil;
for (tmp = quark_class, nc = 0; CONSP (tmp); tmp = XCDR (tmp), nc++)
if (!STRINGP (XCAR (tmp)))
return Qnil;
if (nn != nc)
return Qnil;
else
{
tmp = xrm_q_get_resource (database, quark_name, quark_class);
hash_put (h, key, tmp, hash_code);
return tmp;
}
}
#if TARGET_API_MAC_CARBON
static Lisp_Object
xrm_cfproperty_list_to_value (plist)
CFPropertyListRef plist;
{
CFTypeID type_id = CFGetTypeID (plist);
if (type_id == CFStringGetTypeID ())
return cfstring_to_lisp (plist);
else if (type_id == CFNumberGetTypeID ())
{
CFStringRef string;
Lisp_Object result = Qnil;
string = CFStringCreateWithFormat (NULL, NULL, CFSTR ("%@"), plist);
if (string)
{
result = cfstring_to_lisp (string);
CFRelease (string);
}
return result;
}
else if (type_id == CFBooleanGetTypeID ())
return build_string (CFBooleanGetValue (plist) ? "true" : "false");
else if (type_id == CFDataGetTypeID ())
return cfdata_to_lisp (plist);
else
return Qnil;
}
#endif
XrmDatabase
xrm_get_preference_database (application)
const char *application;
{
#if TARGET_API_MAC_CARBON
CFStringRef app_id, *keys, user_doms[2], host_doms[2];
CFMutableSetRef key_set = NULL;
CFArrayRef key_array;
CFIndex index, count;
char *res_name;
XrmDatabase database;
Lisp_Object quarks = Qnil, value = Qnil;
CFPropertyListRef plist;
int iu, ih;
struct gcpro gcpro1, gcpro2, gcpro3;
user_doms[0] = kCFPreferencesCurrentUser;
user_doms[1] = kCFPreferencesAnyUser;
host_doms[0] = kCFPreferencesCurrentHost;
host_doms[1] = kCFPreferencesAnyHost;
database = xrm_create_database ();
GCPRO3 (database, quarks, value);
BLOCK_INPUT;
app_id = kCFPreferencesCurrentApplication;
if (application)
{
app_id = cfstring_create_with_utf8_cstring (application);
if (app_id == NULL)
goto out;
}
if (!CFPreferencesAppSynchronize (app_id))
goto out;
key_set = CFSetCreateMutable (NULL, 0, &kCFCopyStringSetCallBacks);
if (key_set == NULL)
goto out;
for (iu = 0; iu < sizeof (user_doms) / sizeof (*user_doms) ; iu++)
for (ih = 0; ih < sizeof (host_doms) / sizeof (*host_doms); ih++)
{
key_array = CFPreferencesCopyKeyList (app_id, user_doms[iu],
host_doms[ih]);
if (key_array)
{
count = CFArrayGetCount (key_array);
for (index = 0; index < count; index++)
CFSetAddValue (key_set,
CFArrayGetValueAtIndex (key_array, index));
CFRelease (key_array);
}
}
count = CFSetGetCount (key_set);
keys = xmalloc (sizeof (CFStringRef) * count);
CFSetGetValues (key_set, (const void **)keys);
for (index = 0; index < count; index++)
{
res_name = SDATA (cfstring_to_lisp_nodecode (keys[index]));
quarks = parse_resource_name (&res_name);
if (!(NILP (quarks) || *res_name))
{
plist = CFPreferencesCopyAppValue (keys[index], app_id);
value = xrm_cfproperty_list_to_value (plist);
CFRelease (plist);
if (!NILP (value))
xrm_q_put_resource (database, quarks, value);
}
}
xfree (keys);
out:
if (key_set)
CFRelease (key_set);
CFRelease (app_id);
UNBLOCK_INPUT;
UNGCPRO;
return database;
#else
return xrm_create_database ();
#endif
}
#ifndef MAC_OSX
#define MAC_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
#ifdef __MWERKS__
#if __MSL__ < 0x6000
#define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 70 + 17) * 24 * 60 * 60)
#else
#define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
#endif
#elif __MRC__
#define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
#else
You lose!!!
#endif
int
stat_noalias (const char *path, struct stat *buf)
{
char mac_pathname[MAXPATHLEN+1];
CInfoPBRec cipb;
if (posix_to_mac_pathname (path, mac_pathname, MAXPATHLEN+1) == 0)
return -1;
c2pstr (mac_pathname);
cipb.hFileInfo.ioNamePtr = mac_pathname;
cipb.hFileInfo.ioVRefNum = 0;
cipb.hFileInfo.ioDirID = 0;
cipb.hFileInfo.ioFDirIndex = 0;
errno = PBGetCatInfo (&cipb, false);
if (errno == -43)
errno = ENOENT;
if (errno != noErr)
return -1;
if (cipb.hFileInfo.ioFlAttrib & 0x10)
{
buf->st_mode = S_IFDIR | S_IREAD | S_IEXEC;
if (!(cipb.hFileInfo.ioFlAttrib & 0x1))
buf->st_mode |= S_IWRITE;
buf->st_ino = cipb.dirInfo.ioDrDirID;
buf->st_dev = cipb.dirInfo.ioVRefNum;
buf->st_size = cipb.dirInfo.ioDrNmFls;
buf->st_atime
= buf->st_mtime
= cipb.dirInfo.ioDrMdDat - MAC_UNIX_EPOCH_DIFF;
buf->st_ctime = cipb.dirInfo.ioDrCrDat - MAC_UNIX_EPOCH_DIFF;
}
else
{
buf->st_mode = S_IFREG | S_IREAD;
if (!(cipb.hFileInfo.ioFlAttrib & 0x1))
buf->st_mode |= S_IWRITE;
if (cipb.hFileInfo.ioFlFndrInfo.fdType == 'APPL')
buf->st_mode |= S_IEXEC;
buf->st_ino = cipb.hFileInfo.ioDirID;
buf->st_dev = cipb.hFileInfo.ioVRefNum;
buf->st_size = cipb.hFileInfo.ioFlLgLen;
buf->st_atime
= buf->st_mtime
= cipb.hFileInfo.ioFlMdDat - MAC_UNIX_EPOCH_DIFF;
buf->st_ctime = cipb.hFileInfo.ioFlCrDat - MAC_UNIX_EPOCH_DIFF;
}
if (cipb.hFileInfo.ioFlFndrInfo.fdFlags & 0x8000)
{
buf->st_mode &= ~S_IFREG;
buf->st_mode |= S_IFLNK;
}
buf->st_nlink = 1;
buf->st_uid = getuid ();
buf->st_gid = getgid ();
buf->st_rdev = 0;
return 0;
}
int
lstat (const char *path, struct stat *buf)
{
int result;
char true_pathname[MAXPATHLEN+1];
if ((result = stat_noalias (path, buf)) >= 0)
return result;
if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
return -1;
return stat_noalias (true_pathname, buf);
}
int
stat (const char *path, struct stat *sb)
{
int result;
char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
int len;
if ((result = stat_noalias (path, sb)) >= 0 &&
! (sb->st_mode & S_IFLNK))
return result;
if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
return -1;
len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
if (len > -1)
{
fully_resolved_name[len] = '\0';
return lstat (fully_resolved_name, sb);
}
else
return lstat (true_pathname, sb);
}
#if __MRC__
int
fstat (int fildes, struct stat *buf)
{
buf->st_dev = 0;
buf->st_ino = fildes;
buf->st_mode = S_IFREG;
return 0;
}
#endif
int
mkdir (const char *dirname, int mode)
{
#pragma unused(mode)
HFileParam hfpb;
char true_pathname[MAXPATHLEN+1], mac_pathname[MAXPATHLEN+1];
if (find_true_pathname (dirname, true_pathname, MAXPATHLEN+1) == -1)
return -1;
if (posix_to_mac_pathname (true_pathname, mac_pathname, MAXPATHLEN+1) == 0)
return -1;
c2pstr (mac_pathname);
hfpb.ioNamePtr = mac_pathname;
hfpb.ioVRefNum = 0;
hfpb.ioDirID = 0;
errno = PBDirCreate ((HParmBlkPtr) &hfpb, false);
return errno == noErr ? 0 : -1;
}
#undef rmdir
sys_rmdir (const char *dirname)
{
HFileParam hfpb;
char mac_pathname[MAXPATHLEN+1];
if (posix_to_mac_pathname (dirname, mac_pathname, MAXPATHLEN+1) == 0)
return -1;
c2pstr (mac_pathname);
hfpb.ioNamePtr = mac_pathname;
hfpb.ioVRefNum = 0;
hfpb.ioDirID = 0;
errno = PBHDelete ((HParmBlkPtr) &hfpb, false);
return errno == noErr ? 0 : -1;
}
#ifdef __MRC__
int
execvp (const char *path, ...)
{
return -1;
}
#endif
int
utime (const char *path, const struct utimbuf *times)
{
char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
int len;
char mac_pathname[MAXPATHLEN+1];
CInfoPBRec cipb;
if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
return -1;
len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
if (len > -1)
fully_resolved_name[len] = '\0';
else
strcpy (fully_resolved_name, true_pathname);
if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
return -1;
c2pstr (mac_pathname);
cipb.hFileInfo.ioNamePtr = mac_pathname;
cipb.hFileInfo.ioVRefNum = 0;
cipb.hFileInfo.ioDirID = 0;
cipb.hFileInfo.ioFDirIndex = 0;
errno = PBGetCatInfo (&cipb, false);
if (errno != noErr)
return -1;
if (cipb.hFileInfo.ioFlAttrib & 0x10)
{
if (times)
cipb.dirInfo.ioDrMdDat = times->modtime + MAC_UNIX_EPOCH_DIFF;
else
GetDateTime (&cipb.dirInfo.ioDrMdDat);
}
else
{
if (times)
cipb.hFileInfo.ioFlMdDat = times->modtime + MAC_UNIX_EPOCH_DIFF;
else
GetDateTime (&cipb.hFileInfo.ioFlMdDat);
}
errno = PBSetCatInfo (&cipb, false);
return errno == noErr ? 0 : -1;
}
#ifndef F_OK
#define F_OK 0
#endif
#ifndef X_OK
#define X_OK 1
#endif
#ifndef W_OK
#define W_OK 2
#endif
int
access (const char *path, int mode)
{
char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
int len;
char mac_pathname[MAXPATHLEN+1];
CInfoPBRec cipb;
if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
return -1;
len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
if (len > -1)
fully_resolved_name[len] = '\0';
else
strcpy (fully_resolved_name, true_pathname);
if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
return -1;
c2pstr (mac_pathname);
cipb.hFileInfo.ioNamePtr = mac_pathname;
cipb.hFileInfo.ioVRefNum = 0;
cipb.hFileInfo.ioDirID = 0;
cipb.hFileInfo.ioFDirIndex = 0;
errno = PBGetCatInfo (&cipb, false);
if (errno != noErr)
return -1;
if (mode == F_OK)
return 0;
if (mode & X_OK)
if (cipb.hFileInfo.ioFlAttrib & 0x10)
return 0;
else
{
if (cipb.hFileInfo.ioFlFndrInfo.fdType == 'APPL')
return 0;
else
return -1;
}
if (mode & W_OK)
return (cipb.hFileInfo.ioFlAttrib & 0x1) ? -1 : 0;
return -1;
}
#define DEV_NULL_FD 0x10000
#undef open
int
sys_open (const char *path, int oflag)
{
char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
int len;
char mac_pathname[MAXPATHLEN+1];
if (strcmp (path, "/dev/null") == 0)
return DEV_NULL_FD;
if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
return -1;
len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
if (len > -1)
fully_resolved_name[len] = '\0';
else
strcpy (fully_resolved_name, true_pathname);
if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
return -1;
else
{
#ifdef __MRC__
int res = open (mac_pathname, oflag);
if (oflag & O_CREAT)
fsetfileinfo (mac_pathname, MAC_EMACS_CREATOR_CODE, 'TEXT');
return res;
#else
return open (mac_pathname, oflag);
#endif
}
}
#undef creat
int
sys_creat (const char *path, mode_t mode)
{
char true_pathname[MAXPATHLEN+1];
int len;
char mac_pathname[MAXPATHLEN+1];
if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
return -1;
if (!posix_to_mac_pathname (true_pathname, mac_pathname, MAXPATHLEN+1))
return -1;
else
{
#ifdef __MRC__
int result = creat (mac_pathname);
fsetfileinfo (mac_pathname, MAC_EMACS_CREATOR_CODE, 'TEXT');
return result;
#else
return creat (mac_pathname, mode);
#endif
}
}
#undef unlink
int
sys_unlink (const char *path)
{
char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
int len;
char mac_pathname[MAXPATHLEN+1];
if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
return -1;
len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
if (len > -1)
fully_resolved_name[len] = '\0';
else
strcpy (fully_resolved_name, true_pathname);
if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
return -1;
else
return unlink (mac_pathname);
}
#undef read
int
sys_read (int fildes, char *buf, int count)
{
if (fildes == 0)
return -1;
else
#if __MSL__ >= 0x6000
return _read (fildes, buf, count);
#else
return read (fildes, buf, count);
#endif
}
#undef write
int
sys_write (int fildes, const char *buf, int count)
{
if (fildes == DEV_NULL_FD)
return count;
else
#if __MSL__ >= 0x6000
return _write (fildes, buf, count);
#else
return write (fildes, buf, count);
#endif
}
#undef rename
int
sys_rename (const char * old_name, const char * new_name)
{
char true_old_pathname[MAXPATHLEN+1], true_new_pathname[MAXPATHLEN+1];
char fully_resolved_old_name[MAXPATHLEN+1];
int len;
char mac_old_name[MAXPATHLEN+1], mac_new_name[MAXPATHLEN+1];
if (find_true_pathname (old_name, true_old_pathname, MAXPATHLEN+1) == -1)
return -1;
len = readlink (true_old_pathname, fully_resolved_old_name, MAXPATHLEN);
if (len > -1)
fully_resolved_old_name[len] = '\0';
else
strcpy (fully_resolved_old_name, true_old_pathname);
if (find_true_pathname (new_name, true_new_pathname, MAXPATHLEN+1) == -1)
return -1;
if (strcmp (fully_resolved_old_name, true_new_pathname) == 0)
return 0;
if (!posix_to_mac_pathname (fully_resolved_old_name,
mac_old_name,
MAXPATHLEN+1))
return -1;
if (!posix_to_mac_pathname(true_new_pathname, mac_new_name, MAXPATHLEN+1))
return -1;
(void) unlink (mac_new_name);
return rename (mac_old_name, mac_new_name);
}
#undef fopen
extern FILE *fopen (const char *name, const char *mode);
FILE *
sys_fopen (const char *name, const char *mode)
{
char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
int len;
char mac_pathname[MAXPATHLEN+1];
if (find_true_pathname (name, true_pathname, MAXPATHLEN+1) == -1)
return 0;
len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
if (len > -1)
fully_resolved_name[len] = '\0';
else
strcpy (fully_resolved_name, true_pathname);
if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
return 0;
else
{
#ifdef __MRC__
if (mode[0] == 'w' || mode[0] == 'a')
fsetfileinfo (mac_pathname, MAC_EMACS_CREATOR_CODE, 'TEXT');
#endif
return fopen (mac_pathname, mode);
}
}
extern Boolean mac_wait_next_event P_ ((EventRecord *, UInt32, Boolean));
int
select (nfds, rfds, wfds, efds, timeout)
int nfds;
SELECT_TYPE *rfds, *wfds, *efds;
EMACS_TIME *timeout;
{
OSStatus err = noErr;
if (nfds > 1 || wfds || efds)
return -1;
BLOCK_INPUT;
ENABLE_WAKEUP_FROM_RNE;
if (!detect_input_pending ())
{
#if TARGET_API_MAC_CARBON
EventTimeout timeoutval =
(timeout
? (EMACS_SECS (*timeout) * kEventDurationSecond
+ EMACS_USECS (*timeout) * kEventDurationMicrosecond)
: kEventDurationForever);
if (timeoutval == 0.0)
err = eventLoopTimedOutErr;
else
err = ReceiveNextEvent (0, NULL, timeoutval,
kEventLeaveInQueue, NULL);
#else
EventRecord e;
UInt32 sleep_time = EMACS_SECS (*timeout) * 60 +
((EMACS_USECS (*timeout) * 60) / 1000000);
if (sleep_time == 0)
err = -9875;
else
{
if (mac_wait_next_event (&e, sleep_time, false))
err = noErr;
else
err = -9875;
}
#endif
}
DISABLE_WAKEUP_FROM_RNE;
UNBLOCK_INPUT;
if (err == noErr)
{
detect_input_pending ();
errno = EINTR;
return -1;
}
else
{
if (rfds)
FD_ZERO (rfds);
return 0;
}
}
#include <signal.h>
#include "syssignal.h"
static TMTask mac_atimer_task;
static QElemPtr mac_atimer_qlink = (QElemPtr) &mac_atimer_task;
static int signal_mask = 0;
#ifdef __MRC__
__sigfun alarm_signal_func = (__sigfun) 0;
#elif __MWERKS__
__signal_func_ptr alarm_signal_func = (__signal_func_ptr) 0;
#else
You lose!!!
#endif
#undef signal
#ifdef __MRC__
extern __sigfun signal (int signal, __sigfun signal_func);
__sigfun
sys_signal (int signal_num, __sigfun signal_func)
#elif __MWERKS__
extern __signal_func_ptr signal (int signal, __signal_func_ptr signal_func);
__signal_func_ptr
sys_signal (int signal_num, __signal_func_ptr signal_func)
#else
You lose!!!
#endif
{
if (signal_num != SIGALRM)
return signal (signal_num, signal_func);
else
{
#ifdef __MRC__
__sigfun old_signal_func;
#elif __MWERKS__
__signal_func_ptr old_signal_func;
#else
You lose!!!
#endif
old_signal_func = alarm_signal_func;
alarm_signal_func = signal_func;
return old_signal_func;
}
}
static pascal void
mac_atimer_handler (qlink)
TMTaskPtr qlink;
{
if (alarm_signal_func)
(alarm_signal_func) (SIGALRM);
}
static void
set_mac_atimer (count)
long count;
{
static TimerUPP mac_atimer_handlerUPP = NULL;
if (mac_atimer_handlerUPP == NULL)
mac_atimer_handlerUPP = NewTimerUPP (mac_atimer_handler);
mac_atimer_task.tmCount = 0;
mac_atimer_task.tmAddr = mac_atimer_handlerUPP;
mac_atimer_qlink = (QElemPtr) &mac_atimer_task;
InsTime (mac_atimer_qlink);
if (count)
PrimeTime (mac_atimer_qlink, count);
}
int
remove_mac_atimer (remaining_count)
long *remaining_count;
{
if (mac_atimer_qlink)
{
RmvTime (mac_atimer_qlink);
if (remaining_count)
*remaining_count = mac_atimer_task.tmCount;
mac_atimer_qlink = NULL;
return 0;
}
else
return -1;
}
int
sigblock (int mask)
{
int old_mask = signal_mask;
signal_mask |= mask;
if ((old_mask ^ signal_mask) & sigmask (SIGALRM))
remove_mac_atimer (NULL);
return old_mask;
}
int
sigsetmask (int mask)
{
int old_mask = signal_mask;
signal_mask = mask;
if ((old_mask ^ signal_mask) & sigmask (SIGALRM))
if (signal_mask & sigmask (SIGALRM))
remove_mac_atimer (NULL);
else
set_mac_atimer (mac_atimer_task.tmCount);
return old_mask;
}
int
alarm (int seconds)
{
long remaining_count;
if (remove_mac_atimer (&remaining_count) == 0)
{
set_mac_atimer (seconds * 1000);
return remaining_count / 1000;
}
else
{
mac_atimer_task.tmCount = seconds * 1000;
return 0;
}
}
int
setitimer (which, value, ovalue)
int which;
const struct itimerval *value;
struct itimerval *ovalue;
{
long remaining_count;
long count = (EMACS_SECS (value->it_value) * 1000
+ (EMACS_USECS (value->it_value) + 999) / 1000);
if (remove_mac_atimer (&remaining_count) == 0)
{
if (ovalue)
{
bzero (ovalue, sizeof (*ovalue));
EMACS_SET_SECS_USECS (ovalue->it_value, remaining_count / 1000,
(remaining_count % 1000) * 1000);
}
set_mac_atimer (count);
}
else
mac_atimer_task.tmCount = count;
return 0;
}
int
gettimeofday (tp)
struct timeval *tp;
{
static inited = 0;
static wide wall_clock_at_epoch, clicks_at_epoch;
UnsignedWide uw_microseconds;
wide w_microseconds;
time_t sys_time (time_t *);
if (!inited)
{
time_t systime;
inited = 1;
systime = sys_time (NULL);
WideMultiply (systime, 1000000L, &wall_clock_at_epoch);
Microseconds (&uw_microseconds);
clicks_at_epoch.hi = uw_microseconds.hi;
clicks_at_epoch.lo = uw_microseconds.lo;
}
Microseconds (&uw_microseconds);
w_microseconds.hi = uw_microseconds.hi;
w_microseconds.lo = uw_microseconds.lo;
WideSubtract (&w_microseconds, &clicks_at_epoch);
WideAdd (&w_microseconds, &wall_clock_at_epoch);
tp->tv_sec = WideDivide (&w_microseconds, 1000000L, &tp->tv_usec);
return 0;
}
#ifdef __MRC__
unsigned int
sleep (unsigned int seconds)
{
unsigned long time_up;
EventRecord e;
time_up = TickCount () + seconds * 60;
while (TickCount () < time_up)
{
WaitNextEvent (0, &e, 30, NULL);
}
return (0);
}
#endif
#undef gmtime
extern struct tm *gmtime (const time_t *);
struct tm *
sys_gmtime (const time_t *timer)
{
time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
return gmtime (&unix_time);
}
#undef localtime
extern struct tm *localtime (const time_t *);
struct tm *
sys_localtime (const time_t *timer)
{
#if __MSL__ >= 0x6000
time_t unix_time = *timer;
#else
time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
#endif
return localtime (&unix_time);
}
#undef ctime
extern char *ctime (const time_t *);
char *
sys_ctime (const time_t *timer)
{
#if __MSL__ >= 0x6000
time_t unix_time = *timer;
#else
time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
#endif
return ctime (&unix_time);
}
#undef time
extern time_t time (time_t *);
time_t
sys_time (time_t *timer)
{
#if __MSL__ >= 0x6000
time_t mac_time = time (NULL);
#else
time_t mac_time = time (NULL) - CW_OR_MPW_UNIX_EPOCH_DIFF;
#endif
if (timer)
*timer = mac_time;
return mac_time;
}
int
wait (int pid)
{
return 0;
}
void
croak (char *badfunc)
{
printf ("%s not yet implemented\r\n", badfunc);
exit (1);
}
char *
mktemp (char *template)
{
int len, k;
static seqnum = 0;
len = strlen (template);
k = len - 1;
while (k >= 0 && template[k] == 'X')
k--;
k++;
if (k < len)
{
sprintf (&template[k], "%0*d", len-k, seqnum++);
return template;
}
else
return 0;
}
#define PASSWD_FIELD_SIZE 256
static char my_passwd_name[PASSWD_FIELD_SIZE];
static char my_passwd_dir[MAXPATHLEN+1];
static struct passwd my_passwd =
{
my_passwd_name,
my_passwd_dir,
};
static struct group my_group =
{
"root",
};
char emacs_passwd_dir[MAXPATHLEN+1];
char *
getwd (char *);
void
init_emacs_passwd_dir ()
{
int found = false;
if (getwd (emacs_passwd_dir) && getwd (my_passwd_dir))
{
int len = strlen (emacs_passwd_dir);
int j = len - 1;
int i = j - 1;
while (i >= 0 && !found)
{
while (i >= 0 && emacs_passwd_dir[i] != '/')
i--;
if (emacs_passwd_dir[i] == '/' && i+5 < len)
found = (strncmp (&(emacs_passwd_dir[i+1]), "emacs", 5) == 0);
if (found)
emacs_passwd_dir[j+1] = '\0';
else
{
j = i;
i = j - 1;
}
}
}
if (!found)
{
strcpy (emacs_passwd_dir, "/");
strcpy (my_passwd_dir, "/");
}
}
static struct passwd emacs_passwd =
{
"emacs",
emacs_passwd_dir,
};
static int my_passwd_inited = 0;
static void
init_my_passwd ()
{
char **owner_name;
owner_name = (char **) GetResource ('STR ',-16096);
if (owner_name)
{
HLock (owner_name);
BlockMove ((unsigned char *) *owner_name,
(unsigned char *) my_passwd_name,
*owner_name[0]+1);
HUnlock (owner_name);
p2cstr ((unsigned char *) my_passwd_name);
}
else
my_passwd_name[0] = 0;
}
struct passwd *
getpwuid (uid_t uid)
{
if (!my_passwd_inited)
{
init_my_passwd ();
my_passwd_inited = 1;
}
return &my_passwd;
}
struct group *
getgrgid (gid_t gid)
{
return &my_group;
}
struct passwd *
getpwnam (const char *name)
{
if (strcmp (name, "emacs") == 0)
return &emacs_passwd;
if (!my_passwd_inited)
{
init_my_passwd ();
my_passwd_inited = 1;
}
return &my_passwd;
}
int
fork ()
{
return -1;
}
int
kill (int x, int y)
{
return -1;
}
void
sys_subshell ()
{
error ("Can't spawn subshell");
}
void
request_sigio (void)
{
}
void
unrequest_sigio (void)
{
}
int
setpgrp ()
{
return 0;
}
int
pipe (int _fildes[2])
{
errno = EACCES;
return -1;
}
int
symlink (const char *name1, const char *name2)
{
errno = ENOENT;
return -1;
}
int
link (const char *name1, const char *name2)
{
errno = ENOENT;
return -1;
}
#endif
static int
path_from_vol_dir_name (char *path, int man_path_len, short vol_ref_num,
long dir_id, ConstStr255Param name)
{
Str255 dir_name;
CInfoPBRec cipb;
OSErr err;
if (strlen (name) > man_path_len)
return 0;
memcpy (dir_name, name, name[0]+1);
memcpy (path, name, name[0]+1);
p2cstr (path);
cipb.dirInfo.ioDrParID = dir_id;
cipb.dirInfo.ioNamePtr = dir_name;
do
{
cipb.dirInfo.ioVRefNum = vol_ref_num;
cipb.dirInfo.ioFDirIndex = -1;
cipb.dirInfo.ioDrDirID = cipb.dirInfo.ioDrParID;
err = PBGetCatInfo (&cipb, false);
if (err != noErr)
return 0;
p2cstr (dir_name);
if (strlen (dir_name) + strlen (path) + 1 >= man_path_len)
return 0;
strcat (dir_name, ":");
strcat (dir_name, path);
strcpy (path, dir_name);
}
while (cipb.dirInfo.ioDrDirID != fsRtDirID);
return 1;
}
#ifndef MAC_OSX
static OSErr
posix_pathname_to_fsspec (ufn, fs)
const char *ufn;
FSSpec *fs;
{
Str255 mac_pathname;
if (posix_to_mac_pathname (ufn, mac_pathname, sizeof (mac_pathname)) == 0)
return fnfErr;
else
{
c2pstr (mac_pathname);
return FSMakeFSSpec (0, 0, mac_pathname, fs);
}
}
static OSErr
fsspec_to_posix_pathname (fs, ufn, ufnbuflen)
const FSSpec *fs;
char *ufn;
int ufnbuflen;
{
char mac_pathname[MAXPATHLEN];
if (path_from_vol_dir_name (mac_pathname, sizeof (mac_pathname) - 1,
fs->vRefNum, fs->parID, fs->name)
&& mac_to_posix_pathname (mac_pathname, ufn, ufnbuflen))
return noErr;
else
return fnfErr;
}
int
readlink (const char *path, char *buf, int bufsiz)
{
char mac_sym_link_name[MAXPATHLEN+1];
OSErr err;
FSSpec fsspec;
Boolean target_is_folder, was_aliased;
Str255 directory_name, mac_pathname;
CInfoPBRec cipb;
if (posix_to_mac_pathname (path, mac_sym_link_name, MAXPATHLEN+1) == 0)
return -1;
c2pstr (mac_sym_link_name);
err = FSMakeFSSpec (0, 0, mac_sym_link_name, &fsspec);
if (err != noErr)
{
errno = ENOENT;
return -1;
}
err = ResolveAliasFile (&fsspec, true, &target_is_folder, &was_aliased);
if (err != noErr || !was_aliased)
{
errno = ENOENT;
return -1;
}
if (path_from_vol_dir_name (mac_pathname, 255, fsspec.vRefNum, fsspec.parID,
fsspec.name) == 0)
{
errno = ENOENT;
return -1;
}
if (mac_to_posix_pathname (mac_pathname, buf, bufsiz) == 0)
{
errno = ENOENT;
return -1;
}
return strlen (buf);
}
static int
find_true_pathname (const char *path, char *buf, int bufsiz)
{
char *q, temp[MAXPATHLEN+1];
const char *p;
int len;
if (bufsiz <= 0 || path == 0 || path[0] == '\0')
return -1;
buf[0] = '\0';
p = path;
if (*p == '/')
q = strchr (p + 1, '/');
else
q = strchr (p, '/');
len = 0;
while (q)
{
strcpy (temp, buf);
strncat (temp, p, q - p);
len = readlink (temp, buf, bufsiz);
if (len <= -1)
{
if (strlen (temp) + 1 > bufsiz)
return -1;
strcpy (buf, temp);
}
strcat (buf, "/");
len++;
p = q + 1;
q = strchr(p, '/');
}
if (len + strlen (p) + 1 >= bufsiz)
return -1;
strcat (buf, p);
return len + strlen (p);
}
mode_t
umask (mode_t numask)
{
static mode_t mask = 022;
mode_t oldmask = mask;
mask = numask;
return oldmask;
}
int
chmod (const char *path, mode_t mode)
{
return 0;
}
int
fchmod (int fd, mode_t mode)
{
return 0;
}
int
fchown (int fd, uid_t owner, gid_t group)
{
return 0;
}
int
dup (int oldd)
{
#ifdef __MRC__
return fcntl (oldd, F_DUPFD, 0);
#elif __MWERKS__
return fcntl (oldd, F_DUPFD);
#else
You lose!!!
#endif
}
int
dup2 (int oldd, int newd)
{
int fd, ret;
close (newd);
fd = dup (oldd);
if (fd == -1)
return -1;
if (fd == newd)
return newd;
ret = dup2 (oldd, newd);
close (fd);
return ret;
}
char *
sbrk (int incr)
{
return (char *) -1;
}
int
fsync (int fd)
{
return 0;
}
int
ioctl (int d, int request, void *argp)
{
return -1;
}
#ifdef __MRC__
int
isatty (int fildes)
{
if (fildes >=0 && fildes <= 2)
return 1;
else
return 0;
}
int
getgid ()
{
return 100;
}
int
getegid ()
{
return 100;
}
int
getuid ()
{
return 200;
}
int
geteuid ()
{
return 200;
}
#endif
#ifdef __MWERKS__
#if __MSL__ < 0x6000
#undef getpid
int
getpid ()
{
return 9999;
}
#endif
#endif
#endif
char *
get_temp_dir_name ()
{
static char *temp_dir_name = NULL;
short vol_ref_num;
long dir_id;
OSErr err;
Str255 full_path;
char unix_dir_name[MAXPATHLEN+1];
DIR *dir;
if (!temp_dir_name)
{
err = FindFolder (kOnSystemDisk, kPreferencesFolderType, kCreateFolder,
&vol_ref_num, &dir_id);
if (err != noErr)
return NULL;
if (!path_from_vol_dir_name (full_path, 255, vol_ref_num, dir_id, "\p"))
return NULL;
if (strlen (full_path) + 6 <= MAXPATHLEN)
strcat (full_path, "Emacs:");
else
return NULL;
if (!mac_to_posix_pathname (full_path, unix_dir_name, MAXPATHLEN+1))
return NULL;
dir = opendir (unix_dir_name);
if (dir)
closedir (dir);
else if (mkdir (unix_dir_name, 0700) != 0)
return NULL;
temp_dir_name = (char *) malloc (strlen (unix_dir_name) + 1);
strcpy (temp_dir_name, unix_dir_name);
}
return temp_dir_name;
}
#ifndef MAC_OSX
void
get_string_list (char ***t, short string_list_id)
{
Handle h;
Ptr p;
int i, num_strings;
h = GetResource ('STR#', string_list_id);
if (h)
{
HLock (h);
p = *h;
num_strings = * (short *) p;
p += sizeof(short);
*t = (char **) malloc (sizeof (char *) * (num_strings + 1));
for (i = 0; i < num_strings; i++)
{
short length = *p++;
(*t)[i] = (char *) malloc (length + 1);
strncpy ((*t)[i], p, length);
(*t)[i][length] = '\0';
p += length;
}
(*t)[num_strings] = 0;
HUnlock (h);
}
else
{
*t = (char **) malloc (sizeof (char *));
(*t)[0] = 0;
}
}
static char *
get_path_to_system_folder ()
{
short vol_ref_num;
long dir_id;
OSErr err;
Str255 full_path;
static char system_folder_unix_name[MAXPATHLEN+1];
DIR *dir;
err = FindFolder (kOnSystemDisk, kSystemFolderType, kDontCreateFolder,
&vol_ref_num, &dir_id);
if (err != noErr)
return NULL;
if (!path_from_vol_dir_name (full_path, 255, vol_ref_num, dir_id, "\p"))
return NULL;
if (!mac_to_posix_pathname (full_path, system_folder_unix_name,
MAXPATHLEN+1))
return NULL;
return system_folder_unix_name;
}
char **environ;
#define ENVIRON_STRING_LIST_ID 128
void
init_environ ()
{
int i;
get_string_list (&environ, ENVIRON_STRING_LIST_ID);
i = 0;
while (environ[i])
i++;
if (getenv ("HOME") == NULL)
{
environ = (char **) realloc (environ, sizeof (char *) * (i + 2));
if (environ)
{
environ[i] = (char *) malloc (strlen (my_passwd_dir) + 6);
if (environ[i])
{
strcpy (environ[i], "HOME=");
strcat (environ[i], my_passwd_dir);
}
environ[i+1] = 0;
i++;
}
}
if (getenv ("MAIL") == NULL)
{
environ = (char **) realloc (environ, sizeof (char *) * (i + 2));
if (environ)
{
char * path_to_system_folder = get_path_to_system_folder ();
environ[i] = (char *) malloc (strlen (path_to_system_folder) + 22);
if (environ[i])
{
strcpy (environ[i], "MAIL=");
strcat (environ[i], path_to_system_folder);
strcat (environ[i], "Eudora Folder/In");
}
environ[i+1] = 0;
}
}
}
char *
getenv (const char *name)
{
int length = strlen(name);
char **e;
for (e = environ; *e != 0; e++)
if (strncmp(*e, name, length) == 0 && (*e)[length] == '=')
return &(*e)[length + 1];
if (strcmp (name, "TMPDIR") == 0)
return get_temp_dir_name ();
return 0;
}
#ifdef __MRC__
char *sys_siglist[] =
{
"Zero is not a signal!!!",
"Abort",
"Interactive user interrupt", "?",
"Floating point exception", "?", "?", "?",
"Illegal instruction", "?", "?", "?", "?", "?", "?", "?",
"Segment violation", "?", "?", "?", "?", "?", "?", "?",
"?", "?", "?", "?", "?", "?", "?", "?",
"Terminal"
};
#elif __MWERKS__
char *sys_siglist[] =
{
"Zero is not a signal!!!",
"Abort",
"Floating point exception",
"Illegal instruction",
"Interactive user interrupt",
"Segment violation",
"Terminal"
};
#else
You lose!!!
#endif
#include <utsname.h>
int
uname (struct utsname *name)
{
char **system_name;
system_name = GetString (-16413);
if (system_name)
{
BlockMove (*system_name, name->nodename, (*system_name)[0]+1);
p2cstr (name->nodename);
return 0;
}
else
return -1;
}
const OSType kEmacsSubprocessSend = 'ESND';
const OSType kEmacsSubprocessReply = 'ERPY';
char *
mystrchr (char *s, char c)
{
while (*s && *s != c)
{
if (*s == '\\')
s++;
s++;
}
if (*s)
{
*s = '\0';
return s;
}
else
return NULL;
}
char *
mystrtok (char *s)
{
while (*s)
s++;
return s + 1;
}
void
mystrcpy (char *to, char *from)
{
while (*from)
{
if (*from == '\\')
from++;
*to++ = *from++;
}
*to = '\0';
}
int
run_mac_command (argv, workdir, infn, outfn, errfn)
unsigned char **argv;
const char *workdir;
const char *infn, *outfn, *errfn;
{
#if TARGET_API_MAC_CARBON
return -1;
#else
char macappname[MAXPATHLEN+1], macworkdir[MAXPATHLEN+1];
char macinfn[MAXPATHLEN+1], macoutfn[MAXPATHLEN+1], macerrfn[MAXPATHLEN+1];
int paramlen, argc, newargc, j, retries;
char **newargv, *param, *p;
OSErr iErr;
FSSpec spec;
LaunchParamBlockRec lpbr;
EventRecord send_event, reply_event;
RgnHandle cursor_region_handle;
TargetID targ;
unsigned long ref_con, len;
if (posix_to_mac_pathname (workdir, macworkdir, MAXPATHLEN+1) == 0)
return -1;
if (posix_to_mac_pathname (infn, macinfn, MAXPATHLEN+1) == 0)
return -1;
if (posix_to_mac_pathname (outfn, macoutfn, MAXPATHLEN+1) == 0)
return -1;
if (posix_to_mac_pathname (errfn, macerrfn, MAXPATHLEN+1) == 0)
return -1;
paramlen = strlen (macworkdir) + strlen (macinfn) + strlen (macoutfn)
+ strlen (macerrfn) + 4;
argc = 0;
while (argv[argc])
argc++;
if (argc == 0)
return -1;
j = strlen (argv[0]);
if (j >= 3 && strcmp (argv[0]+j-3, "/sh") == 0
&& argc == 3 && strcmp (argv[1], "-c") == 0)
{
char *command, *t, tempmacpathname[MAXPATHLEN+1];
command = (char *) alloca (strlen (argv[2])+2);
strcpy (command, argv[2]);
if (command[strlen (command) - 1] != ' ')
strcat (command, " ");
t = command;
newargc = 0;
t = mystrchr (t, ' ');
while (t)
{
newargc++;
t = mystrchr (t+1, ' ');
}
newargv = (char **) alloca (sizeof (char *) * newargc);
t = command;
for (j = 0; j < newargc; j++)
{
newargv[j] = (char *) alloca (strlen (t) + 1);
mystrcpy (newargv[j], t);
t = mystrtok (t);
paramlen += strlen (newargv[j]) + 1;
}
if (strncmp (newargv[0], "~emacs/", 7) == 0)
{
if (posix_to_mac_pathname (newargv[0], tempmacpathname, MAXPATHLEN+1)
== 0)
return -1;
}
else
{
#if 0
char *t = (char *) alloca (strlen (newargv[0]) + 7 + 1);
strcpy (t, "~emacs/");
strcat (t, newargv[0]);
#endif
Lisp_Object path;
openp (Vexec_path, build_string (newargv[0]), Vexec_suffixes, &path,
make_number (X_OK));
if (NILP (path))
return -1;
if (posix_to_mac_pathname (SDATA (path), tempmacpathname,
MAXPATHLEN+1) == 0)
return -1;
}
strcpy (macappname, tempmacpathname);
}
else
{
if (posix_to_mac_pathname (argv[0], macappname, MAXPATHLEN+1) == 0)
return -1;
newargv = (char **) alloca (sizeof (char *) * argc);
newargc = argc;
for (j = 1; j < argc; j++)
{
if (strncmp (argv[j], "~emacs/", 7) == 0)
{
char *t = strchr (argv[j], ' ');
if (t)
{
char tempcmdname[MAXPATHLEN+1], tempmaccmdname[MAXPATHLEN+1];
strncpy (tempcmdname, argv[j], t-argv[j]);
tempcmdname[t-argv[j]] = '\0';
if (posix_to_mac_pathname (tempcmdname, tempmaccmdname,
MAXPATHLEN+1) == 0)
return -1;
newargv[j] = (char *) alloca (strlen (tempmaccmdname)
+ strlen (t) + 1);
strcpy (newargv[j], tempmaccmdname);
strcat (newargv[j], t);
}
else
{
char tempmaccmdname[MAXPATHLEN+1];
if (posix_to_mac_pathname (argv[j], tempmaccmdname,
MAXPATHLEN+1) == 0)
return -1;
newargv[j] = (char *) alloca (strlen (tempmaccmdname)+1);
strcpy (newargv[j], tempmaccmdname);
}
}
else
newargv[j] = argv[j];
paramlen += strlen (newargv[j]) + 1;
}
}
param = (char *) malloc (paramlen + 1);
if (!param)
return -1;
p = param;
*p++ = newargc;
strcpy (p, macworkdir);
p += strlen (macworkdir);
*p++ = '\0';
strcpy (p, macinfn);
p += strlen (macinfn);
*p++ = '\0';
strcpy (p, macoutfn);
p += strlen (macoutfn);
*p++ = '\0';
strcpy (p, macerrfn);
p += strlen (macerrfn);
*p++ = '\0';
for (j = 1; j < newargc; j++)
{
strcpy (p, newargv[j]);
p += strlen (newargv[j]);
*p++ = '\0';
}
c2pstr (macappname);
iErr = FSMakeFSSpec (0, 0, macappname, &spec);
if (iErr != noErr)
{
free (param);
return -1;
}
lpbr.launchBlockID = extendedBlock;
lpbr.launchEPBLength = extendedBlockLen;
lpbr.launchControlFlags = launchContinue + launchNoFileFlags;
lpbr.launchAppSpec = &spec;
lpbr.launchAppParameters = NULL;
iErr = LaunchApplication (&lpbr);
if (iErr != noErr)
{
free (param);
return -1;
}
send_event.what = kHighLevelEvent;
send_event.message = kEmacsSubprocessSend;
retries = 3;
do
{
iErr = PostHighLevelEvent (&send_event, &lpbr.launchProcessSN, 0, param,
paramlen + 1, receiverIDisPSN);
}
while (iErr == sessClosedErr && retries-- > 0);
if (iErr != noErr)
{
free (param);
return -1;
}
cursor_region_handle = NewRgn ();
while (1)
if (WaitNextEvent (highLevelEventMask, &reply_event, 180,
cursor_region_handle)
&& reply_event.message == kEmacsSubprocessReply)
break;
iErr = AcceptHighLevelEvent (&targ, &ref_con, NULL, &len);
if (iErr != noErr)
{
DisposeHandle ((Handle) cursor_region_handle);
free (param);
return -1;
}
DisposeHandle ((Handle) cursor_region_handle);
free (param);
return ref_con;
#endif
}
DIR *
opendir (const char *dirname)
{
char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
char mac_pathname[MAXPATHLEN+1], vol_name[MAXPATHLEN+1];
DIR *dirp;
CInfoPBRec cipb;
HVolumeParam vpb;
int len, vol_name_len;
if (find_true_pathname (dirname, true_pathname, MAXPATHLEN+1) == -1)
return 0;
len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
if (len > -1)
fully_resolved_name[len] = '\0';
else
strcpy (fully_resolved_name, true_pathname);
dirp = (DIR *) malloc (sizeof(DIR));
if (!dirp)
return 0;
if (strcmp (fully_resolved_name, "/") == 0)
{
dirp->getting_volumes = 1;
dirp->current_index = 1;
return dirp;
}
if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
return 0;
len = strlen (mac_pathname);
if (mac_pathname[len - 1] != ':' && len < MAXPATHLEN)
strcat (mac_pathname, ":");
vol_name_len = strchr (mac_pathname, ':') - mac_pathname;
strncpy (vol_name, mac_pathname, vol_name_len);
vol_name[vol_name_len] = '\0';
strcat (vol_name, ":");
c2pstr (mac_pathname);
cipb.hFileInfo.ioNamePtr = mac_pathname;
cipb.hFileInfo.ioVRefNum = 0;
cipb.hFileInfo.ioDirID = 0;
cipb.hFileInfo.ioFDirIndex = 0;
errno = PBGetCatInfo (&cipb, false);
if (errno != noErr)
{
errno = ENOENT;
return 0;
}
if (!(cipb.hFileInfo.ioFlAttrib & 0x10))
return 0;
dirp->dir_id = cipb.dirInfo.ioDrDirID;
dirp->getting_volumes = 0;
dirp->current_index = 1;
c2pstr (vol_name);
vpb.ioNamePtr = vol_name;
vpb.ioVRefNum = 0;
vpb.ioVolIndex = -1;
errno = PBHGetVInfo ((union HParamBlockRec *) &vpb, false);
if (errno != noErr)
{
errno = ENOENT;
return 0;
}
dirp->vol_ref_num = vpb.ioVRefNum;
return dirp;
}
int
closedir (DIR *dp)
{
free (dp);
return 0;
}
struct dirent *
readdir (DIR *dp)
{
HParamBlockRec hpblock;
CInfoPBRec cipb;
static struct dirent s_dirent;
static Str255 s_name;
int done;
char *p;
if (dp->getting_volumes)
{
hpblock.volumeParam.ioNamePtr = s_name;
hpblock.volumeParam.ioVRefNum = 0;
hpblock.volumeParam.ioVolIndex = dp->current_index;
errno = PBHGetVInfo (&hpblock, false);
if (errno != noErr)
{
errno = ENOENT;
return 0;
}
p2cstr (s_name);
strcat (s_name, "/");
dp->current_index++;
s_dirent.d_ino = hpblock.volumeParam.ioVRefNum;
s_dirent.d_name = s_name;
return &s_dirent;
}
else
{
cipb.hFileInfo.ioVRefNum = dp->vol_ref_num;
cipb.hFileInfo.ioNamePtr = s_name;
done = false;
while (!done)
{
cipb.hFileInfo.ioDirID = dp->dir_id;
cipb.hFileInfo.ioFDirIndex = dp->current_index;
errno = PBGetCatInfo (&cipb, false);
if (errno != noErr)
{
errno = ENOENT;
return 0;
}
if (cipb.hFileInfo.ioFlAttrib & 0x10)
done = !(cipb.dirInfo.ioDrUsrWds.frFlags & fInvisible);
else
done = !(cipb.hFileInfo.ioFlFndrInfo.fdFlags & fInvisible);
dp->current_index++;
}
p2cstr (s_name);
p = s_name;
while (*p)
{
if (*p == '/')
*p = ':';
p++;
}
s_dirent.d_ino = cipb.dirInfo.ioDrDirID;
s_dirent.d_name = s_name;
return &s_dirent;
}
}
char *
getwd (char *path)
{
char mac_pathname[MAXPATHLEN+1];
Str255 directory_name;
OSErr errno;
CInfoPBRec cipb;
if (path_from_vol_dir_name (mac_pathname, 255, 0, 0, "\p") == 0)
return NULL;
if (mac_to_posix_pathname (mac_pathname, path, MAXPATHLEN+1) == 0)
return 0;
else
return path;
}
#endif
void
initialize_applescript ()
{
AEDesc null_desc;
OSAError osaerror;
as_scripting_component = OpenDefaultComponent (kOSAComponentType,
kAppleScriptSubtype);
null_desc.descriptorType = typeNull;
null_desc.dataHandle = 0;
osaerror = OSAMakeContext (as_scripting_component, &null_desc,
kOSANullScript, &as_script_context);
if (osaerror)
as_script_context = kOSANullScript;
}
void
terminate_applescript()
{
OSADispose (as_scripting_component, as_script_context);
CloseComponent (as_scripting_component);
}
OSType
mac_get_code_from_arg(Lisp_Object arg, OSType defCode)
{
OSType result;
if (NILP(arg))
{
result = defCode;
}
else
{
CHECK_STRING(arg);
if (SBYTES (arg) != 4)
{
error ("Wrong argument: need string of length 4 for code");
}
result = EndianU32_BtoN (*((UInt32 *) SDATA (arg)));
}
return result;
}
Lisp_Object
mac_get_object_from_code(OSType defCode)
{
UInt32 code = EndianU32_NtoB (defCode);
return make_unibyte_string ((char *)&code, 4);
}
DEFUN ("mac-get-file-creator", Fmac_get_file_creator, Smac_get_file_creator, 1, 1, 0,
doc: )
(filename)
Lisp_Object filename;
{
OSStatus status;
#ifdef MAC_OSX
FSRef fref;
#else
FSSpec fss;
#endif
Lisp_Object result = Qnil;
CHECK_STRING (filename);
if (NILP(Ffile_exists_p(filename)) || !NILP(Ffile_directory_p(filename))) {
return Qnil;
}
filename = Fexpand_file_name (filename, Qnil);
BLOCK_INPUT;
#ifdef MAC_OSX
status = FSPathMakeRef(SDATA(ENCODE_FILE(filename)), &fref, NULL);
#else
status = posix_pathname_to_fsspec (SDATA (ENCODE_FILE (filename)), &fss);
#endif
if (status == noErr)
{
#ifdef MAC_OSX
FSCatalogInfo catalogInfo;
status = FSGetCatalogInfo(&fref, kFSCatInfoFinderInfo,
&catalogInfo, NULL, NULL, NULL);
#else
FInfo finder_info;
status = FSpGetFInfo (&fss, &finder_info);
#endif
if (status == noErr)
{
#ifdef MAC_OSX
result = mac_get_object_from_code(((FileInfo*)&catalogInfo.finderInfo)->fileCreator);
#else
result = mac_get_object_from_code (finder_info.fdCreator);
#endif
}
}
UNBLOCK_INPUT;
if (status != noErr) {
error ("Error while getting file information.");
}
return result;
}
DEFUN ("mac-get-file-type", Fmac_get_file_type, Smac_get_file_type, 1, 1, 0,
doc: )
(filename)
Lisp_Object filename;
{
OSStatus status;
#ifdef MAC_OSX
FSRef fref;
#else
FSSpec fss;
#endif
Lisp_Object result = Qnil;
CHECK_STRING (filename);
if (NILP(Ffile_exists_p(filename)) || !NILP(Ffile_directory_p(filename))) {
return Qnil;
}
filename = Fexpand_file_name (filename, Qnil);
BLOCK_INPUT;
#ifdef MAC_OSX
status = FSPathMakeRef(SDATA(ENCODE_FILE(filename)), &fref, NULL);
#else
status = posix_pathname_to_fsspec (SDATA (ENCODE_FILE (filename)), &fss);
#endif
if (status == noErr)
{
#ifdef MAC_OSX
FSCatalogInfo catalogInfo;
status = FSGetCatalogInfo(&fref, kFSCatInfoFinderInfo,
&catalogInfo, NULL, NULL, NULL);
#else
FInfo finder_info;
status = FSpGetFInfo (&fss, &finder_info);
#endif
if (status == noErr)
{
#ifdef MAC_OSX
result = mac_get_object_from_code(((FileInfo*)&catalogInfo.finderInfo)->fileType);
#else
result = mac_get_object_from_code (finder_info.fdType);
#endif
}
}
UNBLOCK_INPUT;
if (status != noErr) {
error ("Error while getting file information.");
}
return result;
}
DEFUN ("mac-set-file-creator", Fmac_set_file_creator, Smac_set_file_creator, 1, 2, 0,
doc: )
(filename, code)
Lisp_Object filename, code;
{
OSStatus status;
#ifdef MAC_OSX
FSRef fref;
#else
FSSpec fss;
#endif
OSType cCode;
CHECK_STRING (filename);
cCode = mac_get_code_from_arg(code, MAC_EMACS_CREATOR_CODE);
if (NILP(Ffile_exists_p(filename)) || !NILP(Ffile_directory_p(filename))) {
return Qnil;
}
filename = Fexpand_file_name (filename, Qnil);
BLOCK_INPUT;
#ifdef MAC_OSX
status = FSPathMakeRef(SDATA(ENCODE_FILE(filename)), &fref, NULL);
#else
status = posix_pathname_to_fsspec (SDATA (ENCODE_FILE (filename)), &fss);
#endif
if (status == noErr)
{
#ifdef MAC_OSX
FSCatalogInfo catalogInfo;
FSRef parentDir;
status = FSGetCatalogInfo(&fref, kFSCatInfoFinderInfo,
&catalogInfo, NULL, NULL, &parentDir);
#else
FInfo finder_info;
status = FSpGetFInfo (&fss, &finder_info);
#endif
if (status == noErr)
{
#ifdef MAC_OSX
((FileInfo*)&catalogInfo.finderInfo)->fileCreator = cCode;
status = FSSetCatalogInfo(&fref, kFSCatInfoFinderInfo, &catalogInfo);
#else
finder_info.fdCreator = cCode;
status = FSpSetFInfo (&fss, &finder_info);
#endif
}
}
UNBLOCK_INPUT;
if (status != noErr) {
error ("Error while setting creator information.");
}
return Qt;
}
DEFUN ("mac-set-file-type", Fmac_set_file_type, Smac_set_file_type, 2, 2, 0,
doc: )
(filename, code)
Lisp_Object filename, code;
{
OSStatus status;
#ifdef MAC_OSX
FSRef fref;
#else
FSSpec fss;
#endif
OSType cCode;
CHECK_STRING (filename);
cCode = mac_get_code_from_arg(code, 0);
if (NILP(Ffile_exists_p(filename)) || !NILP(Ffile_directory_p(filename))) {
return Qnil;
}
filename = Fexpand_file_name (filename, Qnil);
BLOCK_INPUT;
#ifdef MAC_OSX
status = FSPathMakeRef(SDATA(ENCODE_FILE(filename)), &fref, NULL);
#else
status = posix_pathname_to_fsspec (SDATA (ENCODE_FILE (filename)), &fss);
#endif
if (status == noErr)
{
#ifdef MAC_OSX
FSCatalogInfo catalogInfo;
FSRef parentDir;
status = FSGetCatalogInfo(&fref, kFSCatInfoFinderInfo,
&catalogInfo, NULL, NULL, &parentDir);
#else
FInfo finder_info;
status = FSpGetFInfo (&fss, &finder_info);
#endif
if (status == noErr)
{
#ifdef MAC_OSX
((FileInfo*)&catalogInfo.finderInfo)->fileType = cCode;
status = FSSetCatalogInfo(&fref, kFSCatInfoFinderInfo, &catalogInfo);
#else
finder_info.fdType = cCode;
status = FSpSetFInfo (&fss, &finder_info);
#endif
}
}
UNBLOCK_INPUT;
if (status != noErr) {
error ("Error while setting creator information.");
}
return Qt;
}
static long
do_applescript (script, result)
Lisp_Object script, *result;
{
AEDesc script_desc, result_desc, error_desc, *desc = NULL;
OSErr error;
OSAError osaerror;
*result = Qnil;
if (!as_scripting_component)
initialize_applescript();
error = AECreateDesc (typeChar, SDATA (script), SBYTES (script),
&script_desc);
if (error)
return error;
osaerror = OSADoScript (as_scripting_component, &script_desc, kOSANullScript,
typeChar, kOSAModeNull, &result_desc);
if (osaerror == noErr)
desc = &result_desc;
else if (osaerror == errOSAScriptError)
if (!OSAScriptError (as_scripting_component, kOSAErrorMessage, typeChar,
&error_desc))
desc = &error_desc;
if (desc)
{
#if TARGET_API_MAC_CARBON
*result = make_uninit_string (AEGetDescDataSize (desc));
AEGetDescData (desc, SDATA (*result), SBYTES (*result));
#else
*result = make_uninit_string (GetHandleSize (desc->dataHandle));
memcpy (SDATA (*result), *(desc->dataHandle), SBYTES (*result));
#endif
AEDisposeDesc (desc);
}
AEDisposeDesc (&script_desc);
return osaerror;
}
DEFUN ("do-applescript", Fdo_applescript, Sdo_applescript, 1, 1, 0,
doc: )
(script)
Lisp_Object script;
{
Lisp_Object result;
long status;
CHECK_STRING (script);
BLOCK_INPUT;
status = do_applescript (script, &result);
UNBLOCK_INPUT;
if (status == 0)
return result;
else if (!STRINGP (result))
error ("AppleScript error %d", status);
else
error ("%s", SDATA (result));
}
DEFUN ("mac-file-name-to-posix", Fmac_file_name_to_posix,
Smac_file_name_to_posix, 1, 1, 0,
doc: )
(filename)
Lisp_Object filename;
{
char posix_filename[MAXPATHLEN+1];
CHECK_STRING (filename);
if (mac_to_posix_pathname (SDATA (filename), posix_filename, MAXPATHLEN))
return build_string (posix_filename);
else
return Qnil;
}
DEFUN ("posix-file-name-to-mac", Fposix_file_name_to_mac,
Sposix_file_name_to_mac, 1, 1, 0,
doc: )
(filename)
Lisp_Object filename;
{
char mac_filename[MAXPATHLEN+1];
CHECK_STRING (filename);
if (posix_to_mac_pathname (SDATA (filename), mac_filename, MAXPATHLEN))
return build_string (mac_filename);
else
return Qnil;
}
DEFUN ("mac-coerce-ae-data", Fmac_coerce_ae_data, Smac_coerce_ae_data, 3, 3, 0,
doc: )
(src_type, src_data, dst_type)
Lisp_Object src_type, src_data, dst_type;
{
OSErr err;
Lisp_Object result = Qnil;
DescType src_desc_type, dst_desc_type;
AEDesc dst_desc;
CHECK_STRING (src_data);
if (EQ (src_type, Qundecoded_file_name))
src_desc_type = TYPE_FILE_NAME;
else
src_desc_type = mac_get_code_from_arg (src_type, 0);
if (EQ (dst_type, Qundecoded_file_name))
dst_desc_type = TYPE_FILE_NAME;
else
dst_desc_type = mac_get_code_from_arg (dst_type, 0);
BLOCK_INPUT;
err = AECoercePtr (src_desc_type, SDATA (src_data), SBYTES (src_data),
dst_desc_type, &dst_desc);
if (err == noErr)
{
result = Fcdr (mac_aedesc_to_lisp (&dst_desc));
AEDisposeDesc (&dst_desc);
}
UNBLOCK_INPUT;
return result;
}
#if TARGET_API_MAC_CARBON
static Lisp_Object Qxml, Qmime_charset;
static Lisp_Object QNFD, QNFKD, QNFC, QNFKC, QHFS_plus_D, QHFS_plus_C;
DEFUN ("mac-get-preference", Fmac_get_preference, Smac_get_preference, 1, 4, 0,
doc: )
(key, application, format, hash_bound)
Lisp_Object key, application, format, hash_bound;
{
CFStringRef app_id, key_str;
CFPropertyListRef app_plist = NULL, plist;
Lisp_Object result = Qnil, tmp;
struct gcpro gcpro1, gcpro2;
if (STRINGP (key))
key = Fcons (key, Qnil);
else
{
CHECK_CONS (key);
for (tmp = key; CONSP (tmp); tmp = XCDR (tmp))
CHECK_STRING_CAR (tmp);
CHECK_LIST_END (tmp, key);
}
if (!NILP (application))
CHECK_STRING (application);
CHECK_SYMBOL (format);
if (!NILP (hash_bound))
CHECK_NUMBER (hash_bound);
GCPRO2 (key, format);
BLOCK_INPUT;
app_id = kCFPreferencesCurrentApplication;
if (!NILP (application))
{
app_id = cfstring_create_with_string (application);
if (app_id == NULL)
goto out;
}
if (!CFPreferencesAppSynchronize (app_id))
goto out;
key_str = cfstring_create_with_string (XCAR (key));
if (key_str == NULL)
goto out;
app_plist = CFPreferencesCopyAppValue (key_str, app_id);
CFRelease (key_str);
if (app_plist == NULL)
goto out;
plist = app_plist;
for (key = XCDR (key); CONSP (key); key = XCDR (key))
{
if (CFGetTypeID (plist) != CFDictionaryGetTypeID ())
break;
key_str = cfstring_create_with_string (XCAR (key));
if (key_str == NULL)
goto out;
plist = CFDictionaryGetValue (plist, key_str);
CFRelease (key_str);
if (plist == NULL)
goto out;
}
if (NILP (key))
{
if (EQ (format, Qxml))
{
CFDataRef data = CFPropertyListCreateXMLData (NULL, plist);
if (data == NULL)
goto out;
result = cfdata_to_lisp (data);
CFRelease (data);
}
else
result =
cfproperty_list_to_lisp (plist, EQ (format, Qt),
NILP (hash_bound) ? -1 : XINT (hash_bound));
}
out:
if (app_plist)
CFRelease (app_plist);
CFRelease (app_id);
UNBLOCK_INPUT;
UNGCPRO;
return result;
}
static CFStringEncoding
get_cfstring_encoding_from_lisp (obj)
Lisp_Object obj;
{
CFStringRef iana_name;
CFStringEncoding encoding = kCFStringEncodingInvalidId;
if (NILP (obj))
return kCFStringEncodingUnicode;
if (INTEGERP (obj))
return XINT (obj);
if (SYMBOLP (obj) && !NILP (Fcoding_system_p (obj)))
{
Lisp_Object coding_spec, plist;
coding_spec = Fget (obj, Qcoding_system);
plist = XVECTOR (coding_spec)->contents[3];
obj = Fplist_get (XVECTOR (coding_spec)->contents[3], Qmime_charset);
}
if (SYMBOLP (obj))
obj = SYMBOL_NAME (obj);
if (STRINGP (obj))
{
iana_name = cfstring_create_with_string (obj);
if (iana_name)
{
encoding = CFStringConvertIANACharSetNameToEncoding (iana_name);
CFRelease (iana_name);
}
}
return encoding;
}
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
static CFStringRef
cfstring_create_normalized (str, symbol)
CFStringRef str;
Lisp_Object symbol;
{
int form = -1;
TextEncodingVariant variant;
float initial_mag = 0.0;
CFStringRef result = NULL;
if (EQ (symbol, QNFD))
form = kCFStringNormalizationFormD;
else if (EQ (symbol, QNFKD))
form = kCFStringNormalizationFormKD;
else if (EQ (symbol, QNFC))
form = kCFStringNormalizationFormC;
else if (EQ (symbol, QNFKC))
form = kCFStringNormalizationFormKC;
else if (EQ (symbol, QHFS_plus_D))
{
variant = kUnicodeHFSPlusDecompVariant;
initial_mag = 1.5;
}
else if (EQ (symbol, QHFS_plus_C))
{
variant = kUnicodeHFSPlusCompVariant;
initial_mag = 1.0;
}
if (form >= 0)
{
CFMutableStringRef mut_str = CFStringCreateMutableCopy (NULL, 0, str);
if (mut_str)
{
CFStringNormalize (mut_str, form);
result = mut_str;
}
}
else if (initial_mag > 0.0)
{
UnicodeToTextInfo uni = NULL;
UnicodeMapping map;
CFIndex length;
UniChar *in_text, *buffer = NULL, *out_buf = NULL;
OSStatus err = noErr;
ByteCount out_read, out_size, out_len;
map.unicodeEncoding = CreateTextEncoding (kTextEncodingUnicodeDefault,
kUnicodeNoSubset,
kTextEncodingDefaultFormat);
map.otherEncoding = CreateTextEncoding (kTextEncodingUnicodeDefault,
variant,
kTextEncodingDefaultFormat);
map.mappingVersion = kUnicodeUseLatestMapping;
length = CFStringGetLength (str);
out_size = (int)((float)length * initial_mag) * sizeof (UniChar);
if (out_size < 32)
out_size = 32;
in_text = (UniChar *)CFStringGetCharactersPtr (str);
if (in_text == NULL)
{
buffer = xmalloc (sizeof (UniChar) * length);
CFStringGetCharacters (str, CFRangeMake (0, length), buffer);
in_text = buffer;
}
if (in_text)
err = CreateUnicodeToTextInfo (&map, &uni);
while (err == noErr)
{
out_buf = xmalloc (out_size);
err = ConvertFromUnicodeToText (uni, length * sizeof (UniChar),
in_text,
kUnicodeDefaultDirectionMask,
0, NULL, NULL, NULL,
out_size, &out_read, &out_len,
out_buf);
if (err == noErr && out_read < length * sizeof (UniChar))
{
xfree (out_buf);
out_size += length;
}
else
break;
}
if (err == noErr)
result = CFStringCreateWithCharacters (NULL, out_buf,
out_len / sizeof (UniChar));
if (uni)
DisposeUnicodeToTextInfo (&uni);
if (out_buf)
xfree (out_buf);
if (buffer)
xfree (buffer);
}
else
{
result = str;
CFRetain (result);
}
return result;
}
#endif
DEFUN ("mac-code-convert-string", Fmac_code_convert_string, Smac_code_convert_string, 3, 4, 0,
doc: )
(string, source, target, normalization_form)
Lisp_Object string, source, target, normalization_form;
{
Lisp_Object result = Qnil;
struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
CFStringEncoding src_encoding, tgt_encoding;
CFStringRef str = NULL;
CHECK_STRING (string);
if (!INTEGERP (source) && !STRINGP (source))
CHECK_SYMBOL (source);
if (!INTEGERP (target) && !STRINGP (target))
CHECK_SYMBOL (target);
CHECK_SYMBOL (normalization_form);
GCPRO4 (string, source, target, normalization_form);
BLOCK_INPUT;
src_encoding = get_cfstring_encoding_from_lisp (source);
tgt_encoding = get_cfstring_encoding_from_lisp (target);
string = Fstring_as_unibyte (string);
if (src_encoding != kCFStringEncodingInvalidId
&& tgt_encoding != kCFStringEncodingInvalidId)
str = CFStringCreateWithBytes (NULL, SDATA (string), SBYTES (string),
src_encoding, !NILP (source));
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
if (str)
{
CFStringRef saved_str = str;
str = cfstring_create_normalized (saved_str, normalization_form);
CFRelease (saved_str);
}
#endif
if (str)
{
CFIndex str_len, buf_len;
str_len = CFStringGetLength (str);
if (CFStringGetBytes (str, CFRangeMake (0, str_len), tgt_encoding, 0,
!NILP (target), NULL, 0, &buf_len) == str_len)
{
result = make_uninit_string (buf_len);
CFStringGetBytes (str, CFRangeMake (0, str_len), tgt_encoding, 0,
!NILP (target), SDATA (result), buf_len, NULL);
}
CFRelease (str);
}
UNBLOCK_INPUT;
UNGCPRO;
return result;
}
DEFUN ("mac-process-hi-command", Fmac_process_hi_command, Smac_process_hi_command, 1, 1, 0,
doc: )
(command_id)
Lisp_Object command_id;
{
OSStatus err;
HICommand command;
bzero (&command, sizeof (HICommand));
command.commandID = mac_get_code_from_arg (command_id, 0);
BLOCK_INPUT;
err = ProcessHICommand (&command);
UNBLOCK_INPUT;
if (err != noErr)
error ("HI command (command ID: '%s') not handled.", SDATA (command_id));
return Qnil;
}
#endif
static Lisp_Object
mac_get_system_locale ()
{
Lisp_Object object = Qnil;
CFLocaleRef locale = CFLocaleCopyCurrent();
if (locale) {
CFStringRef string = CFLocaleGetValue(locale, kCFLocaleIdentifier);
if (string) {
CFDataRef data = CFStringCreateExternalRepresentation(kCFAllocatorDefault, string, kCFStringEncodingUTF8, 0);
if (data) {
const UInt8 *sdata = CFDataGetBytePtr(data);
if (sdata)
object = build_string(sdata);
CFRelease(data);
}
CFRelease(string);
}
CFRelease(locale);
}
return object;
}
#ifdef MAC_OSX
extern int inhibit_window_system;
extern int noninteractive;
#ifndef SELECT_USE_CFSOCKET
#define SELECT_USE_CFSOCKET 1
#endif
#define SELECT_POLLING_PERIOD_USEC 100000
#if SELECT_USE_CFSOCKET
#define SELECT_TIMEOUT_THRESHOLD_RUNLOOP 0.2
static void
socket_callback (s, type, address, data, info)
CFSocketRef s;
CFSocketCallBackType type;
CFDataRef address;
const void *data;
void *info;
{
int fd = CFSocketGetNative (s);
SELECT_TYPE *ofds = (SELECT_TYPE *)info;
if ((type == kCFSocketReadCallBack && FD_ISSET (fd, &ofds[0]))
|| (type == kCFSocketConnectCallBack && FD_ISSET (fd, &ofds[1])))
QuitEventLoop (GetCurrentEventLoop ());
}
#endif
static int
select_and_poll_event (nfds, rfds, wfds, efds, timeout)
int nfds;
SELECT_TYPE *rfds, *wfds, *efds;
EMACS_TIME *timeout;
{
OSStatus err = noErr;
int r = 0;
BLOCK_INPUT;
ENABLE_WAKEUP_FROM_RNE;
if (!detect_input_pending ())
{
EMACS_TIME select_timeout;
EventTimeout timeoutval =
(timeout
? (EMACS_SECS (*timeout) * kEventDurationSecond
+ EMACS_USECS (*timeout) * kEventDurationMicrosecond)
: kEventDurationForever);
EMACS_SET_SECS_USECS (select_timeout, 0, 0);
r = select (nfds, rfds, wfds, efds, &select_timeout);
if (timeoutval == 0.0)
err = eventLoopTimedOutErr;
else if (r == 0)
{
#if USE_CG_DRAWING
mac_prepare_for_quickdraw (NULL);
#endif
err = ReceiveNextEvent (0, NULL, timeoutval,
kEventLeaveInQueue, NULL);
}
}
DISABLE_WAKEUP_FROM_RNE;
UNBLOCK_INPUT;
if (r != 0)
return r;
else if (err == noErr)
{
detect_input_pending ();
errno = EINTR;
return -1;
}
else
return 0;
}
int
sys_select (nfds, rfds, wfds, efds, timeout)
int nfds;
SELECT_TYPE *rfds, *wfds, *efds;
EMACS_TIME *timeout;
{
OSStatus err = noErr;
int r;
EMACS_TIME select_timeout;
static SELECT_TYPE ofds[3];
if (inhibit_window_system || noninteractive
|| nfds < 1 || rfds == NULL || !FD_ISSET (0, rfds))
return select (nfds, rfds, wfds, efds, timeout);
FD_CLR (0, rfds);
ofds[0] = *rfds;
if (wfds)
ofds[1] = *wfds;
else
FD_ZERO (&ofds[1]);
if (efds)
ofds[2] = *efds;
else
{
EventTimeout timeoutval =
(timeout
? (EMACS_SECS (*timeout) * kEventDurationSecond
+ EMACS_USECS (*timeout) * kEventDurationMicrosecond)
: kEventDurationForever);
FD_SET (0, rfds);
do
{
nfds--;
}
while (!(FD_ISSET (nfds, rfds) || (wfds && FD_ISSET (nfds, wfds))));
nfds++;
FD_CLR (0, rfds);
if (nfds == 1)
return select_and_poll_event (nfds, rfds, wfds, efds, timeout);
EMACS_SET_SECS_USECS (select_timeout, 0, 0);
r = select_and_poll_event (nfds, rfds, wfds, efds, &select_timeout);
if (r != 0 || timeoutval == 0.0)
return r;
*rfds = ofds[0];
if (wfds)
*wfds = ofds[1];
#if SELECT_USE_CFSOCKET
if (timeoutval > 0 && timeoutval <= SELECT_TIMEOUT_THRESHOLD_RUNLOOP)
goto poll_periodically;
BLOCK_INPUT;
ENABLE_WAKEUP_FROM_RNE;
if (!detect_input_pending ())
{
int minfd, fd;
CFRunLoopRef runloop =
(CFRunLoopRef) GetCFRunLoopFromEventLoop (GetCurrentEventLoop ());
static const CFSocketContext context = {0, ofds, NULL, NULL, NULL};
static CFMutableDictionaryRef sources;
if (sources == NULL)
sources =
CFDictionaryCreateMutable (NULL, 0, NULL,
&kCFTypeDictionaryValueCallBacks);
for (minfd = 1; ; minfd++)
if (FD_ISSET (minfd, rfds) || (wfds && FD_ISSET (minfd, wfds)))
break;
for (fd = minfd; fd < nfds; fd++)
if (FD_ISSET (fd, rfds) || (wfds && FD_ISSET (fd, wfds)))
{
void *key = (void *) fd;
CFRunLoopSourceRef source =
(CFRunLoopSourceRef) CFDictionaryGetValue (sources, key);
if (source == NULL)
{
CFSocketRef socket =
CFSocketCreateWithNative (NULL, fd,
(kCFSocketReadCallBack
| kCFSocketConnectCallBack),
socket_callback, &context);
if (socket == NULL)
continue;
source = CFSocketCreateRunLoopSource (NULL, socket, 0);
CFRelease (socket);
if (source == NULL)
continue;
CFDictionaryAddValue (sources, key, source);
CFRelease (source);
}
CFRunLoopAddSource (runloop, source, kCFRunLoopDefaultMode);
}
#if USE_CG_DRAWING
mac_prepare_for_quickdraw (NULL);
#endif
err = ReceiveNextEvent (0, NULL, timeoutval,
kEventLeaveInQueue, NULL);
for (fd = minfd; fd < nfds; fd++)
if (FD_ISSET (fd, rfds) || (wfds && FD_ISSET (fd, wfds)))
{
void *key = (void *) fd;
CFRunLoopSourceRef source =
(CFRunLoopSourceRef) CFDictionaryGetValue (sources, key);
CFRunLoopRemoveSource (runloop, source, kCFRunLoopDefaultMode);
}
}
DISABLE_WAKEUP_FROM_RNE;
UNBLOCK_INPUT;
if (err == noErr || err == eventLoopQuitErr)
{
EMACS_SET_SECS_USECS (select_timeout, 0, 0);
return select_and_poll_event (nfds, rfds, wfds, efds,
&select_timeout);
}
else
{
FD_ZERO (rfds);
if (wfds)
FD_ZERO (wfds);
return 0;
}
#endif
}
poll_periodically:
{
EMACS_TIME end_time, now, remaining_time;
if (timeout)
{
remaining_time = *timeout;
EMACS_GET_TIME (now);
EMACS_ADD_TIME (end_time, now, remaining_time);
}
do
{
EMACS_SET_SECS_USECS (select_timeout, 0, SELECT_POLLING_PERIOD_USEC);
if (timeout && EMACS_TIME_LT (remaining_time, select_timeout))
select_timeout = remaining_time;
r = select_and_poll_event (nfds, rfds, wfds, efds, &select_timeout);
if (r != 0)
return r;
*rfds = ofds[0];
if (wfds)
*wfds = ofds[1];
if (efds)
*efds = ofds[2];
if (timeout)
{
EMACS_GET_TIME (now);
EMACS_SUB_TIME (remaining_time, end_time, now);
}
}
while (!timeout || EMACS_TIME_LT (now, end_time));
EMACS_SET_SECS_USECS (select_timeout, 0, 0);
return select_and_poll_event (nfds, rfds, wfds, efds, &select_timeout);
}
}
void
init_mac_osx_environment ()
{
CFBundleRef bundle;
CFURLRef bundleURL;
CFStringRef cf_app_bundle_pathname;
int app_bundle_pathname_len;
char *app_bundle_pathname;
char *p, *q;
struct stat st;
mac_system_script_code =
(ScriptCode) GetScriptManagerVariable (smSysScript);
Vmac_system_locale = mac_get_system_locale ();
bundle = CFBundleGetMainBundle ();
if (!bundle || CFBundleGetIdentifier (bundle) == NULL)
{
inhibit_window_system = 1;
return;
}
bundleURL = CFBundleCopyBundleURL (bundle);
if (!bundleURL)
return;
cf_app_bundle_pathname = CFURLCopyFileSystemPath (bundleURL,
kCFURLPOSIXPathStyle);
app_bundle_pathname_len = CFStringGetLength (cf_app_bundle_pathname);
app_bundle_pathname = (char *) alloca (app_bundle_pathname_len + 1);
if (!CFStringGetCString (cf_app_bundle_pathname,
app_bundle_pathname,
app_bundle_pathname_len + 1,
kCFStringEncodingISOLatin1))
{
CFRelease (cf_app_bundle_pathname);
return;
}
CFRelease (cf_app_bundle_pathname);
p = (char *) alloca (app_bundle_pathname_len + 50);
q = (char *) alloca (3 * app_bundle_pathname_len + 150);
if (!getenv ("EMACSLOADPATH"))
{
q[0] = '\0';
strcpy (p, app_bundle_pathname);
strcat (p, "/Contents/Resources/lisp");
if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
strcat (q, p);
strcpy (p, app_bundle_pathname);
strcat (p, "/Contents/Resources/leim");
if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
{
if (q[0] != '\0')
strcat (q, ":");
strcat (q, p);
}
strcpy (p, app_bundle_pathname);
strcat (p, "/Contents/Resources/site-lisp");
if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
{
if (q[0] != '\0')
strcat (q, ":");
strcat (q, p);
}
if (q[0] != '\0')
setenv ("EMACSLOADPATH", q, 1);
}
if (!getenv ("EMACSPATH"))
{
q[0] = '\0';
strcpy (p, app_bundle_pathname);
strcat (p, "/Contents/MacOS/libexec");
if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
strcat (q, p);
strcpy (p, app_bundle_pathname);
strcat (p, "/Contents/MacOS/bin");
if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
{
if (q[0] != '\0')
strcat (q, ":");
strcat (q, p);
}
if (q[0] != '\0')
setenv ("EMACSPATH", q, 1);
}
if (!getenv ("EMACSDATA"))
{
strcpy (p, app_bundle_pathname);
strcat (p, "/Contents/Resources/etc");
if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
setenv ("EMACSDATA", p, 1);
}
if (!getenv ("EMACSDOC"))
{
strcpy (p, app_bundle_pathname);
strcat (p, "/Contents/Resources/etc");
if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
setenv ("EMACSDOC", p, 1);
}
if (!getenv ("INFOPATH"))
{
strcpy (p, app_bundle_pathname);
strcat (p, "/Contents/Resources/info");
if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
setenv ("INFOPATH", p, 1);
}
}
#endif
#if TARGET_API_MAC_CARBON
void
mac_wakeup_from_rne ()
{
if (wakeup_from_rne_enabled_p)
mac_post_mouse_moved_event ();
}
#endif
void
syms_of_mac ()
{
Qundecoded_file_name = intern ("undecoded-file-name");
staticpro (&Qundecoded_file_name);
#if TARGET_API_MAC_CARBON
Qstring = intern ("string"); staticpro (&Qstring);
Qnumber = intern ("number"); staticpro (&Qnumber);
Qboolean = intern ("boolean"); staticpro (&Qboolean);
Qdate = intern ("date"); staticpro (&Qdate);
Qdata = intern ("data"); staticpro (&Qdata);
Qarray = intern ("array"); staticpro (&Qarray);
Qdictionary = intern ("dictionary"); staticpro (&Qdictionary);
Qxml = intern ("xml");
staticpro (&Qxml);
Qmime_charset = intern ("mime-charset");
staticpro (&Qmime_charset);
QNFD = intern ("NFD"); staticpro (&QNFD);
QNFKD = intern ("NFKD"); staticpro (&QNFKD);
QNFC = intern ("NFC"); staticpro (&QNFC);
QNFKC = intern ("NFKC"); staticpro (&QNFKC);
QHFS_plus_D = intern ("HFS+D"); staticpro (&QHFS_plus_D);
QHFS_plus_C = intern ("HFS+C"); staticpro (&QHFS_plus_C);
#endif
{
int i;
for (i = 0; i < sizeof (ae_attr_table) / sizeof (ae_attr_table[0]); i++)
{
ae_attr_table[i].symbol = intern (ae_attr_table[i].name);
staticpro (&ae_attr_table[i].symbol);
}
}
defsubr (&Smac_coerce_ae_data);
#if TARGET_API_MAC_CARBON
defsubr (&Smac_get_preference);
defsubr (&Smac_code_convert_string);
defsubr (&Smac_process_hi_command);
#endif
defsubr (&Smac_set_file_creator);
defsubr (&Smac_set_file_type);
defsubr (&Smac_get_file_creator);
defsubr (&Smac_get_file_type);
defsubr (&Sdo_applescript);
defsubr (&Smac_file_name_to_posix);
defsubr (&Sposix_file_name_to_mac);
DEFVAR_INT ("mac-system-script-code", &mac_system_script_code,
doc: );
mac_system_script_code = (ScriptCode) GetScriptManagerVariable (smSysScript);
DEFVAR_LISP ("mac-system-locale", &Vmac_system_locale,
doc: );
Vmac_system_locale = mac_get_system_locale ();
}