]> code.delx.au - gnu-emacs/blobdiff - src/mac.c
[WINDOWSNT]: Undef AF_INET6 to disable IPv6 support for w32.
[gnu-emacs] / src / mac.c
index 99e0d44830ba06353efdb21cf3a20ed9870a8cfa..7c3e495f3a939ee9a16dcf7e39cb42c7921ff9dd 100644 (file)
--- a/src/mac.c
+++ b/src/mac.c
@@ -1,5 +1,6 @@
 /* Unix emulation routines for GNU Emacs on the Mac OS.
 /* Unix emulation routines for GNU Emacs on the Mac OS.
-   Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2001, 2002, 2003, 2004,
+                 2005 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
 
 This file is part of GNU Emacs.
 
@@ -15,8 +16,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
 
 /* Contributed by Andrew Choi (akochoi@mac.com).  */
 
 
 /* Contributed by Andrew Choi (akochoi@mac.com).  */
 
@@ -24,40 +25,19 @@ Boston, MA 02111-1307, USA.  */
 
 #include <stdio.h>
 #include <errno.h>
 
 #include <stdio.h>
 #include <errno.h>
-#include <time.h>
-#include <utime.h>
-#include <dirent.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <string.h>
-#include <pwd.h>
-#include <grp.h>
-#include <sys/param.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#if __MWERKS__
-#include <unistd.h>
-#endif
 
 
-#ifdef MAC_OSX
-#undef mktime
-#undef DEBUG
-#undef free
-#undef malloc
-#undef realloc
-#undef init_process
-#include <Carbon/Carbon.h>
-#undef mktime
-#define mktime emacs_mktime
-#undef free
-#define free unexec_free
-#undef malloc
-#define malloc unexec_malloc
-#undef realloc
-#define realloc unexec_realloc
+#include "lisp.h"
+#include "process.h"
 #undef init_process
 #undef init_process
-#define init_process emacs_init_process
-#else /* not MAC_OSX */
+#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 <Files.h>
 #include <MacTypes.h>
 #include <TextUtils.h>
@@ -69,21 +49,38 @@ Boston, MA 02111-1307, USA.  */
 #include <OSA.h>
 #include <AppleScript.h>
 #include <Scrap.h>
 #include <OSA.h>
 #include <AppleScript.h>
 #include <Scrap.h>
-#endif /* not MAC_OSX */
+#include <Events.h>
+#include <Processes.h>
+#include <EPPC.h>
+#include <MacLocales.h>
+#include <Endian.h>
+#endif /* not TARGET_API_MAC_CARBON */
 
 
-#include "lisp.h"
-#include "process.h"
-#include "sysselect.h"
-#include "systime.h"
-#include "blockinput.h"
+#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
+
+/* The system script code. */
+static int mac_system_script_code;
 
 
-Lisp_Object QCLIPBOARD;
+/* The system locale identifier string.  */
+static Lisp_Object Vmac_system_locale;
 
 /* An instance of the AppleScript component.  */
 static ComponentInstance as_scripting_component;
 /* The single script context used for all script executions.  */
 static OSAID as_script_context;
 
 
 /* An instance of the AppleScript component.  */
 static ComponentInstance as_scripting_component;
 /* The single script context used for all script executions.  */
 static OSAID as_script_context;
 
+static OSErr posix_pathname_to_fsspec P_ ((const char *, FSSpec *));
+static OSErr fsspec_to_posix_pathname P_ ((const FSSpec *, char *, int));
 
 /* When converting from Mac to Unix pathnames, /'s in folder names are
    converted to :'s.  This function, used in copying folder names,
 
 /* When converting from Mac to Unix pathnames, /'s in folder names are
    converted to :'s.  This function, used in copying folder names,
@@ -135,149 +132,1541 @@ mac_to_posix_pathname (const char *mfn, char *ufn, int ufnbuflen)
   if (*p == ':')
     p++;
 
   if (*p == ':')
     p++;
 
-  pe = mfn + strlen (mfn);
-  while (p < pe)
+  pe = mfn + strlen (mfn);
+  while (p < pe)
+    {
+      q = strchr (p, ':');
+      if (q)
+       {
+         if (q == p)
+           {  /* two consecutive ':' */
+             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, '/', ':');
+           /* no separator for last one */
+         p = pe;
+       }
+    }
+
+  return 1;
+}
+
+
+extern char *get_temp_dir_name ();
+
+
+/* Convert a Posix pathname to Mac form.  Approximately reverse of the
+   above in algorithm.  */
+
+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;
+
+  /* Check for and handle volume names.  Last comparison: strangely
+     somewhere "/.emacs" is passed.  A temporary fix for now.  */
+  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;
+    }
+
+  /* expand to emacs dir found by init_emacs_passwd_dir */
+  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;
+        /* now p points to the pathname with emacs dir prefix */
+    }
+  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;
+        /* now p points to the pathname with emacs dir prefix */
+    }
+  else if (*p != '/')  /* relative pathname */
+    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;
+}
+
+\f
+/***********************************************************************
+                 Conversions on Apple event objects
+ ***********************************************************************/
+
+static Lisp_Object Qundecoded_file_name;
+
+static Lisp_Object
+mac_aelist_to_lisp (desc_list)
+     AEDescList *desc_list;
+{
+  OSErr err;
+  long count;
+  Lisp_Object result, elem;
+  DescType desc_type;
+  Size size;
+  AEKeyword keyword;
+  AEDesc desc;
+
+  err = AECountItems (desc_list, &count);
+  if (err != noErr)
+    return Qnil;
+  result = Qnil;
+  while (count > 0)
+    {
+      err = AESizeOfNthItem (desc_list, count, &desc_type, &size);
+      if (err == noErr)
+       switch (desc_type)
+         {
+         case typeAEList:
+         case typeAERecord:
+         case typeAppleEvent:
+           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);
+               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)
+       elem = Qnil;
+      else if (desc_list->descriptorType != typeAEList)
+       {
+         keyword = EndianU32_NtoB (keyword);
+         elem = Fcons (make_unibyte_string ((char *) &keyword, 4), elem);
+       }
+
+      result = Fcons (elem, result);
+      count--;
+    }
+
+  desc_type = EndianU32_NtoB (desc_list->descriptorType);
+  return Fcons (make_unibyte_string ((char *) &desc_type, 4), result);
+}
+
+Lisp_Object
+mac_aedesc_to_lisp (desc)
+     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
+      /* The following one is much simpler, but creates and disposes
+        of Apple event descriptors many times.  */
+      {
+       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);
+}
+
+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 == TYPE_FILE_NAME)
+    /* Coercion from undecoded file name.  */
+    switch (to_type)
+      {
+      case typeAlias:
+      case typeFSS:
+      case typeFSRef:
+#ifdef MAC_OSX
+      case typeFileURL:
+#endif
+       {
+#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;
+#else
+         FSSpec fs;
+         char *buf;
+
+         buf = xmalloc (data_size + 1);
+         if (buf)
+           {
+             memcpy (buf, data_ptr, data_size);
+             buf[data_size] = '\0';
+             err = posix_pathname_to_fsspec (buf, &fs);
+             xfree (buf);
+           }
+         else
+           err = memFullErr;
+         if (err == noErr)
+           err = AECoercePtr (typeFSS, &fs, sizeof (FSSpec),
+                              to_type, result);
+#endif
+       }
+       break;
+
+      case TYPE_FILE_NAME:
+      case typeWildCard:
+       err = AECreateDesc (TYPE_FILE_NAME, data_ptr, data_size, result);
+       break;
+
+      default:
+       err = errAECoercionFail;
+       break;
+      }
+  else if (to_type == TYPE_FILE_NAME)
+    /* Coercion to undecoded file name.  */
+    switch (type_code)
+      {
+      case typeAlias:
+      case typeFSS:
+      case typeFSRef:
+#ifdef MAC_OSX
+      case typeFileURL:
+#endif
+       {
+         AEDesc desc;
+#ifdef MAC_OSX
+         Size size;
+         char *buf;
+         CFURLRef url = NULL;
+         CFStringRef str = NULL;
+         CFDataRef data = NULL;
+
+         err = AECoercePtr (type_code, data_ptr, data_size,
+                            typeFileURL, &desc);
+         if (err == noErr)
+           {
+             size = AEGetDescDataSize (&desc);
+             buf = xmalloc (size);
+             if (buf)
+               {
+                 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);
+           }
+         else
+           err = memFullErr;
+#else
+         FSSpec fs;
+         char file_name[MAXPATHLEN];
+
+         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
+             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);
+             AEDisposeDesc (&desc);
+           }
+#endif
+       }
+       break;
+
+      default:
+       err = errAECoercionFail;
+       break;
+      }
+  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 == TYPE_FILE_NAME)
+    {
+      if (to_type != TYPE_FILE_NAME && to_type != typeWildCard
+         && to_type != typeAlias && to_type != typeFSS
+         && to_type != typeFSRef
+#ifdef MAC_OSX
+         && to_type != typeFileURL
+#endif
+         )
+       return errAECoercionFail;
+    }
+  else if (to_type == TYPE_FILE_NAME)
+    {
+      if (from_type != typeAlias && from_type != typeFSS
+         && from_type != typeFSRef
+#ifdef MAC_OSX
+         && from_type != typeFileURL
+#endif
+         )
+       return errAECoercionFail;
+    }
+  else
+    abort ();
+
+  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 (data_ptr)
+       {
+#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);
+       }
+      else
+       err = memFullErr;
+    }
+
+  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
+OSErr
+create_apple_event_from_event_ref (event, num_params, names, types, result)
+     EventRef event;
+     UInt32 num_params;
+     EventParamName *names;
+     EventParamType *types;
+     AppleEvent *result;
+{
+  OSErr err;
+  static const ProcessSerialNumber psn = {0, kCurrentProcess};
+  AEAddressDesc address_desc;
+  UInt32 i, size;
+  CFStringRef string;
+  CFDataRef data;
+  char *buf;
+
+  err = AECreateDesc (typeProcessSerialNumber, &psn,
+                     sizeof (ProcessSerialNumber), &address_desc);
+  if (err == noErr)
+    {
+      err = AECreateAppleEvent (0, 0, /* Dummy class and ID.   */
+                               &address_desc, /* NULL is not allowed
+                                                 on Mac OS Classic. */
+                               kAutoGenerateReturnID,
+                               kAnyTransactionID, result);
+      AEDisposeDesc (&address_desc);
+    }
+  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;
+       /* typeUTF8Text is not available on Mac OS X 10.1.  */
+       AEPutParamPtr (result, names[i], 'utf8',
+                      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 = xmalloc (size);
+       if (buf == NULL)
+         break;
+       err = GetEventParameter (event, names[i], types[i], NULL,
+                                size, NULL, buf);
+       if (err == noErr)
+         AEPutParamPtr (result, names[i], types[i], buf, size);
+       xfree (buf);
+       break;
+      }
+
+  return noErr;
+}
+#endif
+
+\f
+/***********************************************************************
+        Conversion between Lisp and Core Foundation objects
+ ***********************************************************************/
+
+#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;
+};
+
+/* C string to CFString.  */
+
+CFStringRef
+cfstring_create_with_utf8_cstring (c_str)
+     const char *c_str;
+{
+  CFStringRef str;
+
+  str = CFStringCreateWithCString (NULL, c_str, kCFStringEncodingUTF8);
+  if (str == NULL)
+    /* Failed to interpret as UTF 8.  Fall back on Mac Roman.  */
+    str = CFStringCreateWithCString (NULL, c_str, kCFStringEncodingMacRoman);
+
+  return str;
+}
+
+
+/* Lisp string to CFString.  */
+
+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)
+    /* Failed to interpret as UTF 8.  Fall back on Mac Roman.  */
+    string = CFStringCreateWithBytes (NULL, SDATA (s), SBYTES (s),
+                                     kCFStringEncodingMacRoman, false);
+
+  return string;
+}
+
+
+/* From CFData to a lisp string.  Always returns a unibyte 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;
+}
+
+
+/* From CFString to a lisp string.  Returns a unibyte string
+   containing a UTF-8 byte sequence.  */
+
+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;
+}
+
+
+/* From CFString to a lisp string.  Never returns a unibyte string
+   (even if it only contains ASCII characters).
+   This may cause GC during code conversion. */
+
+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);
+      /* This may be superfluous.  Just to make sure that the result
+        is a multibyte string.  */
+      result = string_to_multibyte (result);
+    }
+
+  return result;
+}
+
+
+/* CFNumber to a lisp integer or a lisp float.  */
+
+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;
+}
+
+
+/* CFDate to a list of three integers as in a return value of
+   `current-time'.  */
+
+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));
+}
+
+
+/* CFBoolean to a lisp symbol, `t' or `nil'.  */
+
+Lisp_Object
+cfboolean_to_lisp (boolean)
+     CFBooleanRef boolean;
+{
+  return CFBooleanGetValue (boolean) ? Qt : Qnil;
+}
+
+
+/* Any Core Foundation object to a (lengthy) lisp string.  */
+
+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;
+}
+
+
+/* Callback functions for cfproperty_list_to_lisp.  */
+
+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);
+}
+
+
+/* Convert CFPropertyList PLIST to a lisp object.  If WITH_TAG is
+   non-zero, a symbol that represents the type of the original Core
+   Foundation object is prepended.  HASH_BOUND specifies which kinds
+   of the lisp objects, alists or hash tables, are used as the targets
+   of the conversion from CFDictionary.  If HASH_BOUND is negative,
+   always generate alists.  If HASH_BOUND >= 0, generate an alist if
+   the number of keys in the dictionary is smaller than HASH_BOUND,
+   and a hash table otherwise.  */
+
+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
+
+\f
+/***********************************************************************
+                Emulation of the X Resource Manager
+ ***********************************************************************/
+
+/* Parser functions for resource lines.  Each function takes an
+   address of a variable whose value points to the head of a string.
+   The value will be advanced so that it points to the next character
+   of the parsed part when the function returns.
+
+   A resource name such as "Emacs*font" is parsed into a non-empty
+   list called `quarks'.  Each element is either a Lisp string that
+   represents a concrete component, a Lisp symbol LOOSE_BINDING
+   (actually Qlambda) that represents any number (>=0) of intervening
+   components, or a Lisp symbol SINGLE_COMPONENT (actually Qquote)
+   that represents as any single component.  */
+
+#define P (*p)
+
+#define LOOSE_BINDING    Qlambda /* '*' ("L"oose) */
+#define SINGLE_COMPONENT Qquote         /* '?' ("Q"uestion) */
+
+static void
+skip_white_space (p)
+     char **p;
+{
+  /* WhiteSpace = {<space> | <horizontal tab>} */
+  while (*P == ' ' || *P == '\t')
+    P++;
+}
+
+static int
+parse_comment (p)
+     char **p;
+{
+  /* Comment = "!" {<any character except null or newline>} */
+  if (*P == '!')
+    {
+      P++;
+      while (*P)
+       if (*P++ == '\n')
+         break;
+      return 1;
+    }
+  else
+    return 0;
+}
+
+/* Don't interpret filename.  Just skip until the newline.  */
+static int
+parse_include_file (p)
+     char **p;
+{
+  /* IncludeFile = "#" WhiteSpace "include" WhiteSpace FileName WhiteSpace */
+  if (*P == '#')
+    {
+      P++;
+      while (*P)
+       if (*P++ == '\n')
+         break;
+      return 1;
+    }
+  else
+    return 0;
+}
+
+static char
+parse_binding (p)
+     char **p;
+{
+  /* Binding = "." | "*"  */
+  if (*P == '.' || *P == '*')
+    {
+      char binding = *P++;
+
+      while (*P == '.' || *P == '*')
+       if (*P++ == '*')
+         binding = '*';
+      return binding;
+    }
+  else
+    return '\0';
+}
+
+static Lisp_Object
+parse_component (p)
+     char **p;
+{
+  /*  Component = "?" | ComponentName
+      ComponentName = NameChar {NameChar}
+      NameChar = "a"-"z" | "A"-"Z" | "0"-"9" | "_" | "-" */
+  if (*P == '?')
+    {
+      P++;
+      return SINGLE_COMPONENT;
+    }
+  else if (isalnum (*P) || *P == '_' || *P == '-')
+    {
+      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)
+     char **p;
+{
+  Lisp_Object result = Qnil, component;
+  char binding;
+
+  /* ResourceName = [Binding] {Component Binding} ComponentName */
+  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);
+    }
+
+  /* The final component should not be '?'.  */
+  if (EQ (component, SINGLE_COMPONENT))
+    return Qnil;
+
+  return Fnreverse (result);
+}
+
+static Lisp_Object
+parse_value (p)
+     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)
+     char **p;
+{
+  Lisp_Object quarks, value;
+
+  /* ResourceLine = Comment | IncludeFile | ResourceSpec | <empty line> */
+  if (parse_comment (p) || parse_include_file (p))
+    return Qnil;
+
+  /* ResourceSpec = WhiteSpace ResourceName WhiteSpace ":" WhiteSpace Value */
+  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:
+  /* Skip the remaining data as a dummy value.  */
+  parse_value (p);
+  return Qnil;
+}
+
+#undef P
+
+/* Equivalents of X Resource Manager functions.
+
+   An X Resource Database acts as a collection of resource names and
+   associated values.  It is implemented as a trie on quarks.  Namely,
+   each edge is labeled by either a string, LOOSE_BINDING, or
+   SINGLE_COMPONENT.  Each node has a node id, which is a unique
+   nonnegative integer, and the root node id is 0.  A database is
+   implemented as a hash table that maps a pair (SRC-NODE-ID .
+   EDGE-LABEL) to DEST-NODE-ID.  It also holds a maximum node id used
+   in the table as a value for HASHKEY_MAX_NID.  A value associated to
+   a node is recorded as a value for the node id.
+
+   A database also has a cache for past queries as a value for
+   HASHKEY_QUERY_CACHE.  It is another hash table that maps
+   "NAME-STRING\0CLASS-STRING" to the result of the query.  */
+
+#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))
     {
     {
-      q = strchr (p, ':');
-      if (q)
+      key = Fcons (node_id, XCAR (quarks));
+      i = hash_lookup (h, key, &hash_code);
+      if (i < 0)
        {
        {
-         if (q == p)
-           {  /* two consecutive ':' */
-             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;
+         max_nid++;
+         XSETINT (node_id, max_nid);
+         hash_put (h, key, node_id, hash_code);
        }
       else
        }
       else
-       {
-         if (strlen (ufn) + (pe - p) >= ufnbuflen)
-           return 0;
-         string_cat_and_replace (ufn, p, pe - p, '/', ':');
-           /* no separator for last one */
-         p = pe;
-       }
+       node_id = HASH_VALUE (h, i);
     }
     }
+  Fputhash (node_id, value, database);
 
 
-  return 1;
+  Fputhash (HASHKEY_MAX_NID, make_number (max_nid), database);
+  Fputhash (HASHKEY_QUERY_CACHE, Qnil, database);
 }
 
 }
 
+/* Merge multiple resource entries specified by DATA into a resource
+   database DATABASE.  DATA points to the head of a null-terminated
+   string consisting of multiple resource lines.  It's like a
+   combination of XrmGetStringDatabase and XrmMergeDatabases.  */
 
 
-extern char *get_temp_dir_name ();
-
+void
+xrm_merge_string_database (database, data)
+     XrmDatabase database;
+     char *data;
+{
+  Lisp_Object quarks_value;
 
 
-/* Convert a Posix pathname to Mac form.  Approximately reverse of the
-   above in algorithm.  */
+  while (*data)
+    {
+      quarks_value = parse_resource_line (&data);
+      if (!NILP (quarks_value))
+       xrm_q_put_resource (database,
+                           XCAR (quarks_value), XCDR (quarks_value));
+    }
+}
 
 
-int
-posix_to_mac_pathname (const char *ufn, char *mfn, int mfnbuflen)
+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;
 {
 {
-  const char *p, *q, *pe;
-  char expanded_pathname[MAXPATHLEN+1];
+  struct Lisp_Hash_Table *h = XHASH_TABLE (database);
+  Lisp_Object key, labels[3], value;
+  int i, k;
 
 
-  strcpy (mfn, "");
+  if (!CONSP (quark_name))
+    return Fgethash (node_id, database, Qnil);
 
 
-  if (*ufn == '\0')
-    return 1;
+  /* First, try tight bindings */
+  labels[0] = XCAR (quark_name);
+  labels[1] = XCAR (quark_class);
+  labels[2] = SINGLE_COMPONENT;
 
 
-  p = ufn;
+  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;
+       }
+    }
 
 
-  /* Check for and handle volume names.  Last comparison: strangely
-     somewhere "/.emacs" is passed.  A temporary fix for now.  */
-  if (*p == '/' && strchr (p+1, '/') == NULL && strcmp (p, "/.emacs") != 0)
+  /* Then, try loose bindings */
+  XSETCDR (key, LOOSE_BINDING);
+  i = hash_lookup (h, key, NULL);
+  if (i >= 0)
     {
     {
-      if (strlen (p) + 1 > mfnbuflen)
-       return 0;
-      strcpy (mfn, p+1);
-      strcat (mfn, ":");
-      return 1;
+      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;
+}
 
 
-  /* expand to emacs dir found by init_emacs_passwd_dir */
-  if (strncmp (p, "~emacs/", 7) == 0)
+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);
+}
+
+/* Retrieve a resource value for the specified NAME and CLASS from the
+   resource database DATABASE.  It corresponds to XrmGetResource.  */
+
+Lisp_Object
+xrm_get_resource (database, name, class)
+     XrmDatabase database;
+     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))
     {
     {
-      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;
-        /* now p points to the pathname with emacs dir prefix */
+      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);
     }
     }
-  else if (strncmp (p, "/tmp/", 5) == 0)
+  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
     {
     {
-      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;
-        /* now p points to the pathname with emacs dir prefix */
+      tmp = xrm_q_get_resource (database, quark_name, quark_class);
+      hash_put (h, key, tmp, hash_code);
+      return tmp;
     }
     }
-  else if (*p != '/')  /* relative pathname */
-    strcat (mfn, ":");
+}
 
 
-  if (*p == '/')
-    p++;
+#if TARGET_API_MAC_CARBON
+static Lisp_Object
+xrm_cfproperty_list_to_value (plist)
+     CFPropertyListRef plist;
+{
+  CFTypeID type_id = CFGetTypeID (plist);
 
 
-  pe = p + strlen (p);
-  while (p < pe)
+  if (type_id == CFStringGetTypeID ())
+    return cfstring_to_lisp (plist);
+  else if (type_id == CFNumberGetTypeID ())
     {
     {
-      q = strchr (p, '/');
-      if (q)
+      CFStringRef string;
+      Lisp_Object result = Qnil;
+
+      string = CFStringCreateWithFormat (NULL, NULL, CFSTR ("%@"), plist);
+      if (string)
        {
        {
-         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;
+         result = cfstring_to_lisp (string);
+         CFRelease (string);
        }
        }
-      else
+      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
+
+/* Create a new resource database from the preferences for the
+   application APPLICATION.  APPLICATION is either a string that
+   specifies an application ID, or NULL that represents the current
+   application.  */
+
+XrmDatabase
+xrm_get_preference_database (application)
+     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;
+    }
+
+  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);
+  if (keys == NULL)
+    goto out;
+  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))
        {
        {
-         if (strlen (mfn) + (pe - p) >= mfnbuflen)
-           return 0;
-         string_cat_and_replace (mfn, p, pe - p, ':', '/');
-         p = pe;
+         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);
        }
     }
 
        }
     }
 
-  return 1;
-}
+  xfree (keys);
+ out:
+  if (key_set)
+    CFRelease (key_set);
+  CFRelease (app_id);
 
 
-#if TARGET_API_MAC_CARBON
-CFStringRef
-cfstring_create_with_utf8_cstring (c_str)
-     const char *c_str;
-{
-  CFStringRef str;
+  UNBLOCK_INPUT;
 
 
-  str = CFStringCreateWithCString (NULL, c_str, kCFStringEncodingUTF8);
-  if (str == NULL)
-    /* Failed to interpret as UTF 8.  Fall back on Mac Roman.  */
-    str = CFStringCreateWithCString (NULL, c_str, kCFStringEncodingMacRoman);
+  UNGCPRO;
 
 
-  return str;
-}
+  return database;
+#else
+  return xrm_create_database ();
 #endif
 #endif
+}
 
 
+\f
 #ifndef MAC_OSX
 
 /* The following functions with "sys_" prefix are stubs to Unix
 #ifndef MAC_OSX
 
 /* The following functions with "sys_" prefix are stubs to Unix
@@ -812,9 +2201,90 @@ sys_fopen (const char *name, const char *mode)
 }
 
 
 }
 
 
-#include <Events.h>
+#include "keyboard.h"
+extern Boolean mac_wait_next_event (EventRecord *, UInt32, Boolean);
+
+int
+select (n,  rfds, wfds, efds, timeout)
+  int n;
+  SELECT_TYPE *rfds;
+  SELECT_TYPE *wfds;
+  SELECT_TYPE *efds;
+  struct timeval *timeout;
+{
+  OSErr err;
+#if TARGET_API_MAC_CARBON
+  EventTimeout timeout_sec =
+    (timeout
+     ? (EMACS_SECS (*timeout) * kEventDurationSecond
+       + EMACS_USECS (*timeout) * kEventDurationMicrosecond)
+     : kEventDurationForever);
+
+  BLOCK_INPUT;
+  err = ReceiveNextEvent (0, NULL, timeout_sec, kEventLeaveInQueue, NULL);
+  UNBLOCK_INPUT;
+#else /* not TARGET_API_MAC_CARBON */
+  EventRecord e;
+  UInt32 sleep_time = EMACS_SECS (*timeout) * 60 +
+    ((EMACS_USECS (*timeout) * 60) / 1000000);
+
+  /* Can only handle wait for keyboard input.  */
+  if (n > 1 || wfds || efds)
+    return -1;
+
+  /* Also return true if an event other than a keyDown has occurred.
+     This causes kbd_buffer_get_event in keyboard.c to call
+     read_avail_input which in turn calls XTread_socket to poll for
+     these events.  Otherwise these never get processed except but a
+     very slow poll timer.  */
+  if (mac_wait_next_event (&e, sleep_time, false))
+    err = noErr;
+  else
+    err = -9875;               /* eventLoopTimedOutErr */
+#endif /* not TARGET_API_MAC_CARBON */
+
+  if (FD_ISSET (0, rfds))
+    if (err == noErr)
+      return 1;
+    else
+      {
+       FD_ZERO (rfds);
+       return 0;
+      }
+  else
+    if (err == noErr)
+      {
+       if (input_polling_used ())
+         {
+           /* It could be confusing if a real alarm arrives while
+              processing the fake one.  Turn it off and let the
+              handler reset it.  */
+           extern void poll_for_input_1 P_ ((void));
+           int old_poll_suppress_count = poll_suppress_count;
+           poll_suppress_count = 1;
+           poll_for_input_1 ();
+           poll_suppress_count = old_poll_suppress_count;
+         }
+       errno = EINTR;
+       return -1;
+      }
+    else
+      return 0;
+}
 
 
-long target_ticks = 0;
+
+/* Simulation of SIGALRM.  The stub for function signal stores the
+   signal handler function in alarm_signal_func if a SIGALRM is
+   encountered.  */
+
+#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;
 
 #ifdef __MRC__
 __sigfun alarm_signal_func = (__sigfun) 0;
@@ -824,123 +2294,156 @@ __signal_func_ptr alarm_signal_func = (__signal_func_ptr) 0;
 You lose!!!
 #endif /* not __MRC__ and not __MWERKS__ */
 
 You lose!!!
 #endif /* not __MRC__ and not __MWERKS__ */
 
+#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 /* not __MRC__ and not __MWERKS__ */
+     You lose!!!
+#endif /* not __MRC__ and not __MWERKS__ */
+{
+  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);
+}
 
 
-/* These functions simulate SIG_ALRM.  The stub for function signal
-   stores the signal handler function in alarm_signal_func if a
-   SIG_ALRM is encountered.  check_alarm is called in XTread_socket,
-   which emacs calls periodically.  A pending alarm is represented by
-   a non-zero target_ticks value.  check_alarm calls the handler
-   function pointed to by alarm_signal_func if one has been set up and
-   an alarm is pending.  */
 
 
-void
-check_alarm ()
+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 (target_ticks && TickCount () > target_ticks)
+  if (mac_atimer_qlink)
     {
     {
-      target_ticks = 0;
-      if (alarm_signal_func)
-       (*alarm_signal_func)(SIGALRM);
+      RmvTime (mac_atimer_qlink);
+      if (remaining_count)
+       *remaining_count = mac_atimer_task.tmCount;
+      mac_atimer_qlink = NULL;
+
+      return 0;
     }
     }
+  else
+    return -1;
 }
 
 
 }
 
 
-extern Boolean mac_wait_next_event (EventRecord *, UInt32, Boolean);
-
 int
 int
-select (n,  rfds, wfds, efds, timeout)
-  int n;
-  SELECT_TYPE *rfds;
-  SELECT_TYPE *wfds;
-  SELECT_TYPE *efds;
-  struct timeval *timeout;
+sigblock (int mask)
 {
 {
-#if TARGET_API_MAC_CARBON
-  return 1;
-#else /* not TARGET_API_MAC_CARBON */
-  EventRecord e;
-  UInt32 sleep_time = EMACS_SECS (*timeout) * 60 +
-    ((EMACS_USECS (*timeout) * 60) / 1000000);
+  int old_mask = signal_mask;
 
 
-  /* Can only handle wait for keyboard input.  */
-  if (n > 1 || wfds || efds)
-    return -1;
+  signal_mask |= mask;
 
 
-  /* Also return true if an event other than a keyDown has occurred.
-     This causes kbd_buffer_get_event in keyboard.c to call
-     read_avail_input which in turn calls XTread_socket to poll for
-     these events.  Otherwise these never get processed except but a
-     very slow poll timer.  */
-  if (FD_ISSET (0, rfds) && mac_wait_next_event (&e, sleep_time, false))
-    return 1;
+  if ((old_mask ^ signal_mask) & sigmask (SIGALRM))
+    remove_mac_atimer (NULL);
 
 
-  return 0;
-#endif /* not TARGET_API_MAC_CARBON */
+  return old_mask;
 }
 
 
 }
 
 
-/* Called in sys_select to wait for an alarm signal to arrive.  */
-
 int
 int
-pause ()
+sigsetmask (int mask)
 {
 {
-  EventRecord e;
-  unsigned long tick;
-
-  if (!target_ticks)  /* no alarm pending */
-    return -1;
+  int old_mask = signal_mask;
 
 
-  if ((tick = TickCount ()) < target_ticks)
-    WaitNextEvent (0, &e, target_ticks - tick, NULL); /* Accept no event;
-                                                        just wait. by T.I. */
+  signal_mask = mask;
 
 
-  target_ticks = 0;
-  if (alarm_signal_func)
-    (*alarm_signal_func)(SIGALRM);
+  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 0;
+  return old_mask;
 }
 
 
 int
 alarm (int seconds)
 {
 }
 
 
 int
 alarm (int seconds)
 {
-  long remaining = target_ticks ? (TickCount () - target_ticks) / 60 : 0;
+  long remaining_count;
+
+  if (remove_mac_atimer (&remaining_count) == 0)
+    {
+      set_mac_atimer (seconds * 1000);
 
 
-  target_ticks = seconds ? TickCount () + 60 * seconds : 0;
+      return remaining_count / 1000;
+    }
+  else
+    {
+      mac_atimer_task.tmCount = seconds * 1000;
 
 
-  return (remaining < 0) ? 0 : (unsigned int) remaining;
+      return 0;
+    }
 }
 
 
 }
 
 
-#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 /* not __MRC__ and not __MWERKS__ */
-     You lose!!!
-#endif /* not __MRC__ and not __MWERKS__ */
+int
+setitimer (which, value, ovalue)
+     int which;
+     const struct itimerval *value;
+     struct itimerval *ovalue;
 {
 {
-  if (signal_num != SIGALRM)
-    return signal (signal_num, signal_func);
-  else
+  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)
     {
     {
-#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;
+      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;
 }
 
 
 }
 
 
@@ -1071,35 +2574,6 @@ sys_time (time_t *timer)
 }
 
 
 }
 
 
-/* MPW strftime broken for "%p" format */
-#ifdef __MRC__
-#undef strftime
-#include <time.h>
-size_t
-sys_strftime (char * s, size_t maxsize, const char * format,
-             const struct tm * timeptr)
-{
-  if (strcmp (format, "%p") == 0)
-    {
-      if (maxsize < 3)
-        return 0;
-      if (timeptr->tm_hour < 12)
-        {
-          strcpy (s, "AM");
-          return 2;
-        }
-      else
-        {
-          strcpy (s, "PM");
-          return 2;
-        }
-    }
-  else
-    return strftime (s, maxsize, format, timeptr);
-}
-#endif  /* __MRC__ */
-
-
 /* no subprocesses, empty wait */
 
 int
 /* no subprocesses, empty wait */
 
 int
@@ -1117,13 +2591,6 @@ croak (char *badfunc)
 }
 
 
 }
 
 
-char *
-index (const char * str, int chr)
-{
-  return strchr (str, chr);
-}
-
-
 char *
 mktemp (char *template)
 {
 char *
 mktemp (char *template)
 {
@@ -1312,20 +2779,6 @@ sys_subshell ()
 }
 
 
 }
 
 
-int
-sigsetmask (int x)
-{
-  return 0;
-}
-
-
-int
-sigblock (int mask)
-{
-  return 0;
-}
-
-
 void
 request_sigio (void)
 {
 void
 request_sigio (void)
 {
@@ -1421,6 +2874,39 @@ path_from_vol_dir_name (char *path, int man_path_len, short vol_ref_num,
   return 1;  /* success */
 }
 
   return 1;  /* success */
 }
 
+
+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;
+}
+
 #ifndef MAC_OSX
 
 int
 #ifndef MAC_OSX
 
 int
@@ -1532,6 +3018,22 @@ chmod (const char *path, mode_t mode)
 }
 
 
 }
 
 
+int
+fchmod (int fd, mode_t mode)
+{
+  /* say it always succeed for now */
+  return 0;
+}
+
+
+int
+fchown (int fd, uid_t owner, gid_t group)
+{
+  /* say it always succeed for now */
+  return 0;
+}
+
+
 int
 dup (int oldd)
 {
 int
 dup (int oldd)
 {
@@ -1899,9 +3401,6 @@ uname (struct utsname *name)
 }
 
 
 }
 
 
-#include <Processes.h>
-#include <EPPC.h>
-
 /* Event class of HLE sent to subprocess.  */
 const OSType kEmacsSubprocessSend = 'ESND';
 
 /* Event class of HLE sent to subprocess.  */
 const OSType kEmacsSubprocessSend = 'ESND';
 
@@ -1965,7 +3464,10 @@ mystrcpy (char *to, char *from)
    wildcard filename expansion.  Since we don't really have a shell on
    the Mac, this case is detected and the starting of the shell is
    by-passed.  We really need to add code here to do filename
    wildcard filename expansion.  Since we don't really have a shell on
    the Mac, this case is detected and the starting of the shell is
    by-passed.  We really need to add code here to do filename
-   expansion to support such functionality. */
+   expansion to support such functionality.
+
+   We can't use this strategy in Carbon because the High Level Event
+   APIs are not available.  */
 
 int
 run_mac_command (argv, workdir, infn, outfn, errfn)
 
 int
 run_mac_command (argv, workdir, infn, outfn, errfn)
@@ -2373,154 +3875,389 @@ readdir (DIR *dp)
          dp->current_index++;
        }
 
          dp->current_index++;
        }
 
-      p2cstr (s_name);
+      p2cstr (s_name);
+
+      p = s_name;
+      while (*p)
+        {
+          if (*p == '/')
+            *p = ':';
+          p++;
+        }
+
+      s_dirent.d_ino = cipb.dirInfo.ioDrDirID;
+        /* value unimportant: non-zero for valid file */
+      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  /* ! MAC_OSX */
+
+
+void
+initialize_applescript ()
+{
+  AEDesc null_desc;
+  OSAError osaerror;
+
+  /* if open fails, as_scripting_component is set to NULL.  Its
+     subsequent use in OSA calls will fail with badComponentInstance
+     error.  */
+  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;
+      /* use default context if create fails */
+}
+
+
+void
+terminate_applescript()
+{
+  OSADispose (as_scripting_component, as_script_context);
+  CloseComponent (as_scripting_component);
+}
+
+/* Convert a lisp string to the 4 byte character code.  */
+
+OSType
+mac_get_code_from_arg(Lisp_Object arg, OSType defCode)
+{
+  OSType result;
+  if (NILP(arg))
+    {
+      result = defCode;
+    }
+  else
+    {
+      /* check type string */
+      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;
+}
+
+/* Convert the 4 byte character code into a 4 byte string.  */
+
+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: /* Get the creator code of FILENAME as a four character string. */)
+     (filename)
+     Lisp_Object filename;
+{
+  OSErr        status;
+#ifdef MAC_OSX
+  FSRef fref;
+#else
+  FSSpec fss;
+#endif
+  OSType cCode;
+  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: /* Get the type code of FILENAME as a four character string. */)
+     (filename)
+     Lisp_Object filename;
+{
+  OSErr        status;
+#ifdef MAC_OSX
+  FSRef fref;
+#else
+  FSSpec fss;
+#endif
+  OSType cCode;
+  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);
 
 
-      p = s_name;
-      while (*p)
-        {
-          if (*p == '/')
-            *p = ':';
-          p++;
-        }
+  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
 
 
-      s_dirent.d_ino = cipb.dirInfo.ioDrDirID;
-        /* value unimportant: non-zero for valid file */
-      s_dirent.d_name = s_name;
+  if (status == noErr)
+    {
+#ifdef MAC_OSX
+      FSCatalogInfo catalogInfo;
 
 
-      return &s_dirent;
+      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;
 }
 
 }
 
-
-char *
-getwd (char *path)
+DEFUN ("mac-set-file-creator", Fmac_set_file_creator, Smac_set_file_creator, 1, 2, 0,
+       doc: /* Set creator code of file FILENAME to CODE.
+If non-nil, CODE must be a 4-character string.  Otherwise, 'EMAx' is
+assumed. Return non-nil if successful.  */)
+     (filename, code)
+     Lisp_Object filename, code;
 {
 {
-  char mac_pathname[MAXPATHLEN+1];
-  Str255 directory_name;
-  OSErr errno;
-  CInfoPBRec cipb;
+  OSErr        status;
+#ifdef MAC_OSX
+  FSRef fref;
+#else
+  FSSpec fss;
+#endif
+  OSType cCode;
+  CHECK_STRING (filename);
 
 
-  if (path_from_vol_dir_name (mac_pathname, 255, 0, 0, "\p") == 0)
-    return NULL;
+  cCode = mac_get_code_from_arg(code, 'EMAx');
 
 
-  if (mac_to_posix_pathname (mac_pathname, path, MAXPATHLEN+1) == 0)
-    return 0;
-  else
-    return path;
-}
+  if (NILP(Ffile_exists_p(filename)) || !NILP(Ffile_directory_p(filename))) {
+    return Qnil;
+  }
+  filename = Fexpand_file_name (filename, Qnil);
 
 
-#endif  /* ! MAC_OSX */
+  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;
 
 
-void
-initialize_applescript ()
+      status = FSpGetFInfo (&fss, &finder_info);
+#endif
+      if (status == noErr)
+       {
+#ifdef MAC_OSX
+       ((FileInfo*)&catalogInfo.finderInfo)->fileCreator = cCode;
+       status = FSSetCatalogInfo(&fref, kFSCatInfoFinderInfo, &catalogInfo);
+       /* TODO: on Mac OS 10.2, we need to touch the parent dir, FNNotify? */
+#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: /* Set file code of file FILENAME to CODE.
+CODE must be a 4-character string.  Return non-nil if successful.  */)
+     (filename, code)
+     Lisp_Object filename, code;
 {
 {
-  AEDesc null_desc;
-  OSAError osaerror;
+  OSErr        status;
+#ifdef MAC_OSX
+  FSRef fref;
+#else
+  FSSpec fss;
+#endif
+  OSType cCode;
+  CHECK_STRING (filename);
 
 
-  /* if open fails, as_scripting_component is set to NULL.  Its
-     subsequent use in OSA calls will fail with badComponentInstance
-     error.  */
-  as_scripting_component = OpenDefaultComponent (kOSAComponentType,
-                                                kAppleScriptSubtype);
+  cCode = mac_get_code_from_arg(code, 0); /* Default to empty code*/
 
 
-  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;
-      /* use default context if create fails */
-}
+  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
 
 
-void terminate_applescript()
-{
-  OSADispose (as_scripting_component, as_script_context);
-  CloseComponent (as_scripting_component);
+  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);
+       /* TODO: on Mac OS 10.2, we need to touch the parent dir, FNNotify? */
+#else
+       finder_info.fdType = cCode;
+       status = FSpSetFInfo (&fss, &finder_info);
+#endif
+       }
+    }
+  UNBLOCK_INPUT;
+  if (status != noErr) {
+    error ("Error while setting creator information.");
+  }
+  return Qt;
 }
 
 
 /* Compile and execute the AppleScript SCRIPT and return the error
    status as function value.  A zero is returned if compilation and
 }
 
 
 /* Compile and execute the AppleScript SCRIPT and return the error
    status as function value.  A zero is returned if compilation and
-   execution is successful, in which case RESULT returns a pointer to
-   a string containing the resulting script value.  Otherwise, the Mac
-   error code is returned and RESULT returns a pointer to an error
-   string.  In both cases the caller should deallocate the storage
-   used by the string pointed to by RESULT if it is non-NULL.  For
-   documentation on the MacOS scripting architecture, see Inside
-   Macintosh - Interapplication Communications: Scripting Components.  */
+   execution is successful, in which case *RESULT is set to a Lisp
+   string containing the resulting script value.  Otherwise, the Mac
+   error code is returned and *RESULT is set to an error Lisp string.
+   For documentation on the MacOS scripting architecture, see Inside
+   Macintosh - Interapplication Communications: Scripting
+   Components.  */
 
 static long
 
 static long
-do_applescript (char *script, char **result)
+do_applescript (script, result)
+     Lisp_Object script, *result;
 {
 {
-  AEDesc script_desc, result_desc, error_desc;
+  AEDesc script_desc, result_desc, error_desc, *desc = NULL;
   OSErr error;
   OSAError osaerror;
   OSErr error;
   OSAError osaerror;
-  long length;
 
 
-  *result = 0;
+  *result = Qnil;
 
   if (!as_scripting_component)
     initialize_applescript();
 
 
   if (!as_scripting_component)
     initialize_applescript();
 
-  error = AECreateDesc (typeChar, script, strlen(script), &script_desc);
+  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 (error)
     return error;
 
   osaerror = OSADoScript (as_scripting_component, &script_desc, kOSANullScript,
                          typeChar, kOSAModeNull, &result_desc);
 
-  if (osaerror == errOSAScriptError)
-    {
-      /* error executing AppleScript: retrieve error message */
-      if (!OSAScriptError (as_scripting_component, kOSAErrorMessage, typeChar,
-                          &error_desc))
-        {
-#if TARGET_API_MAC_CARBON
-          length = AEGetDescDataSize (&error_desc);
-          *result = (char *) xmalloc (length + 1);
-          if (*result)
-            {
-              AEGetDescData (&error_desc, *result, length);
-              *(*result + length) = '\0';
-            }
-#else /* not TARGET_API_MAC_CARBON */
-          HLock (error_desc.dataHandle);
-          length = GetHandleSize(error_desc.dataHandle);
-          *result = (char *) xmalloc (length + 1);
-          if (*result)
-            {
-              memcpy (*result, *(error_desc.dataHandle), length);
-              *(*result + length) = '\0';
-            }
-          HUnlock (error_desc.dataHandle);
-#endif /* not TARGET_API_MAC_CARBON */
-          AEDisposeDesc (&error_desc);
-        }
-    }
-  else if (osaerror == noErr)  /* success: retrieve resulting script value */
+  if (osaerror == noErr)
+    /* success: retrieve resulting script value */
+    desc = &result_desc;
+  else if (osaerror == errOSAScriptError)
+    /* error executing AppleScript: retrieve error message */
+    if (!OSAScriptError (as_scripting_component, kOSAErrorMessage, typeChar,
+                        &error_desc))
+      desc = &error_desc;
+
+  if (desc)
     {
 #if TARGET_API_MAC_CARBON
     {
 #if TARGET_API_MAC_CARBON
-      length = AEGetDescDataSize (&result_desc);
-      *result = (char *) xmalloc (length + 1);
-      if (*result)
-        {
-          AEGetDescData (&result_desc, *result, length);
-          *(*result + length) = '\0';
-        }
+      *result = make_uninit_string (AEGetDescDataSize (desc));
+      AEGetDescData (desc, SDATA (*result), SBYTES (*result));
 #else /* not TARGET_API_MAC_CARBON */
 #else /* not TARGET_API_MAC_CARBON */
-      HLock (result_desc.dataHandle);
-      length = GetHandleSize(result_desc.dataHandle);
-      *result = (char *) xmalloc (length + 1);
-      if (*result)
-        {
-          memcpy (*result, *(result_desc.dataHandle), length);
-          *(*result + length) = '\0';
-        }
-      HUnlock (result_desc.dataHandle);
+      *result = make_uninit_string (GetHandleSize (desc->dataHandle));
+      memcpy (SDATA (*result), *(desc->dataHandle), SBYTES (*result));
 #endif /* not TARGET_API_MAC_CARBON */
 #endif /* not TARGET_API_MAC_CARBON */
-      AEDisposeDesc (&result_desc);
+      AEDisposeDesc (desc);
     }
 
   AEDisposeDesc (&script_desc);
     }
 
   AEDisposeDesc (&script_desc);
@@ -2530,61 +4267,42 @@ do_applescript (char *script, char **result)
 
 
 DEFUN ("do-applescript", Fdo_applescript, Sdo_applescript, 1, 1, 0,
 
 
 DEFUN ("do-applescript", Fdo_applescript, Sdo_applescript, 1, 1, 0,
-       doc: /* Compile and execute AppleScript SCRIPT and retrieve and return the result.
+       doc: /* Compile and execute AppleScript SCRIPT and return the result.
 If compilation and execution are successful, the resulting script
 value is returned as a string.  Otherwise the function aborts and
 displays the error message returned by the AppleScript scripting
 component.  */)
 If compilation and execution are successful, the resulting script
 value is returned as a string.  Otherwise the function aborts and
 displays the error message returned by the AppleScript scripting
 component.  */)
-  (script)
+    (script)
     Lisp_Object script;
 {
     Lisp_Object script;
 {
-  char *result, *temp;
-  Lisp_Object lisp_result;
+  Lisp_Object result;
   long status;
 
   CHECK_STRING (script);
 
   BLOCK_INPUT;
   long status;
 
   CHECK_STRING (script);
 
   BLOCK_INPUT;
-  status = do_applescript (SDATA (script), &result);
+  status = do_applescript (script, &result);
   UNBLOCK_INPUT;
   UNBLOCK_INPUT;
-  if (status)
-    {
-      if (!result)
-        error ("AppleScript error %d", status);
-      else
-        {
-          /* Unfortunately only OSADoScript in do_applescript knows how
-             how large the resulting script value or error message is
-             going to be and therefore as caller memory must be
-             deallocated here.  It is necessary to free the error
-             message before calling error to avoid a memory leak.  */
-          temp = (char *) alloca (strlen (result) + 1);
-          strcpy (temp, result);
-          xfree (result);
-          error (temp);
-        }
-    }
+  if (status == 0)
+    return result;
+  else if (!STRINGP (result))
+    error ("AppleScript error %d", status);
   else
   else
-    {
-      lisp_result = build_string (result);
-      xfree (result);
-      return lisp_result;
-    }
+    error ("%s", SDATA (result));
 }
 
 
 DEFUN ("mac-file-name-to-posix", Fmac_file_name_to_posix,
        Smac_file_name_to_posix, 1, 1, 0,
 }
 
 
 DEFUN ("mac-file-name-to-posix", Fmac_file_name_to_posix,
        Smac_file_name_to_posix, 1, 1, 0,
-       doc: /* Convert Macintosh filename to Posix form.  */)
-     (mac_filename)
-     Lisp_Object mac_filename;
+       doc: /* Convert Macintosh FILENAME to Posix form.  */)
+     (filename)
+     Lisp_Object filename;
 {
   char posix_filename[MAXPATHLEN+1];
 
 {
   char posix_filename[MAXPATHLEN+1];
 
-  CHECK_STRING (mac_filename);
+  CHECK_STRING (filename);
 
 
-  if (mac_to_posix_pathname (SDATA (mac_filename), posix_filename,
-                          MAXPATHLEN))
+  if (mac_to_posix_pathname (SDATA (filename), posix_filename, MAXPATHLEN))
     return build_string (posix_filename);
   else
     return Qnil;
     return build_string (posix_filename);
   else
     return Qnil;
@@ -2593,194 +4311,436 @@ DEFUN ("mac-file-name-to-posix", Fmac_file_name_to_posix,
 
 DEFUN ("posix-file-name-to-mac", Fposix_file_name_to_mac,
        Sposix_file_name_to_mac, 1, 1, 0,
 
 DEFUN ("posix-file-name-to-mac", Fposix_file_name_to_mac,
        Sposix_file_name_to_mac, 1, 1, 0,
-       doc: /* Convert Posix filename to Mac form.  */)
-     (posix_filename)
-     Lisp_Object posix_filename;
+       doc: /* Convert Posix FILENAME to Mac form.  */)
+     (filename)
+     Lisp_Object filename;
 {
   char mac_filename[MAXPATHLEN+1];
 
 {
   char mac_filename[MAXPATHLEN+1];
 
-  CHECK_STRING (posix_filename);
+  CHECK_STRING (filename);
 
 
-  if (posix_to_mac_pathname (SDATA (posix_filename), mac_filename,
-                          MAXPATHLEN))
+  if (posix_to_mac_pathname (SDATA (filename), mac_filename, MAXPATHLEN))
     return build_string (mac_filename);
   else
     return Qnil;
 }
 
 
     return build_string (mac_filename);
   else
     return Qnil;
 }
 
 
-/* set interprogram-paste-function to mac-paste-function in mac-win.el
-   to enable Emacs to obtain the contents of the Mac clipboard. */
-DEFUN ("mac-paste-function", Fmac_paste_function, Smac_paste_function, 0, 0, 0,
-       doc: /* Return the contents of the Mac clipboard as a string.  */)
-     ()
+DEFUN ("mac-coerce-ae-data", Fmac_coerce_ae_data, Smac_coerce_ae_data, 3, 3, 0,
+       doc: /* Coerce Apple event data SRC-DATA of type SRC-TYPE to DST-TYPE.
+Each type should be a string of length 4 or the symbol
+`undecoded-file-name'.  */)
+  (src_type, src_data, dst_type)
+     Lisp_Object src_type, src_data, dst_type;
 {
 {
-#if TARGET_API_MAC_CARBON
-  OSStatus err;
-  ScrapRef scrap;
-  ScrapFlavorFlags sff;
-  Size s;
-  int i;
-  char *data;
+  OSErr err;
+  Lisp_Object result = Qnil;
+  DescType src_desc_type, dst_desc_type;
+  AEDesc dst_desc;
+#ifdef MAC_OSX
+  FSRef fref;
+#else
+  FSSpec fs;
+#endif
+
+  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;
 
   BLOCK_INPUT;
-  err = GetCurrentScrap (&scrap);
-  if (err == noErr)
-    err = GetScrapFlavorFlags (scrap, kScrapFlavorTypeText, &sff);
+  err = AECoercePtr (src_desc_type, SDATA (src_data), SBYTES (src_data),
+                    dst_desc_type, &dst_desc);
   if (err == noErr)
   if (err == noErr)
-    err = GetScrapFlavorSize (scrap, kScrapFlavorTypeText, &s);
-  if (err == noErr && (data = (char*) alloca (s)))
-    err = GetScrapFlavorData (scrap, kScrapFlavorTypeText, &s, data);
+    {
+      result = Fcdr (mac_aedesc_to_lisp (&dst_desc));
+      AEDisposeDesc (&dst_desc);
+    }
   UNBLOCK_INPUT;
   UNBLOCK_INPUT;
-  if (err != noErr || s == 0)
-    return Qnil;
 
 
-  /* Emacs expects clipboard contents have Unix-style eol's */
-  for (i = 0; i < s; i++)
-    if (data[i] == '\r')
-      data[i] = '\n';
+  return result;
+}
 
 
-  return make_string (data, s);
-#else /* not TARGET_API_MAC_CARBON */
-  Lisp_Object value;
-  Handle my_handle;
-  long scrap_offset, rc, i;
 
 
-  my_handle = NewHandle (0);  /* allocate 0-length data area */
+#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: /* Return the application preference value for KEY.
+KEY is either a string specifying a preference key, or a list of key
+strings.  If it is a list, the (i+1)-th element is used as a key for
+the CFDictionary value obtained by the i-th element.  Return nil if
+lookup is failed at some stage.
+
+Optional arg APPLICATION is an application ID string.  If omitted or
+nil, that stands for the current application.
+
+Optional arg FORMAT specifies the data format of the return value.  If
+omitted or nil, each Core Foundation object is converted into a
+corresponding Lisp object as follows:
+
+  Core Foundation    Lisp                           Tag
+  ------------------------------------------------------------
+  CFString           Multibyte string               string
+  CFNumber           Integer or float               number
+  CFBoolean          Symbol (t or nil)              boolean
+  CFDate             List of three integers         date
+                       (cf. `current-time')
+  CFData             Unibyte string                 data
+  CFArray            Vector                         array
+  CFDictionary       Alist or hash table            dictionary
+                       (depending on HASH-BOUND)
+
+If it is t, a symbol that represents the type of the original Core
+Foundation object is prepended.  If it is `xml', the value is returned
+as an XML representation.
+
+Optional arg HASH-BOUND specifies which kinds of the list objects,
+alists or hash tables, are used as the targets of the conversion from
+CFDictionary.  If HASH-BOUND is a negative integer or nil, always
+generate alists.  If HASH-BOUND >= 0, generate an alist if the number
+of keys in the dictionary is smaller than HASH-BOUND, and a hash table
+otherwise.  */)
+     (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;
 
 
-  rc = GetScrap (my_handle, 'TEXT', &scrap_offset);
-  if (rc < 0)
-    return Qnil;
+  if (STRINGP (key))
+    key = Fcons (key, Qnil);
+  else
+    {
+      CHECK_CONS (key);
+      for (tmp = key; CONSP (tmp); tmp = XCDR (tmp))
+       CHECK_STRING_CAR (tmp);
+      if (!NILP (tmp))
+       wrong_type_argument (Qlistp, key);
+    }
+  if (!NILP (application))
+    CHECK_STRING (application);
+  CHECK_SYMBOL (format);
+  if (!NILP (hash_bound))
+    CHECK_NUMBER (hash_bound);
 
 
-  HLock (my_handle);
+  BLOCK_INPUT;
 
 
-  /* Emacs expects clipboard contents have Unix-style eol's */
-  for (i = 0; i < rc; i++)
-    if ((*my_handle)[i] == '\r')
-      (*my_handle)[i] = '\n';
+  app_id = kCFPreferencesCurrentApplication;
+  if (!NILP (application))
+    {
+      app_id = cfstring_create_with_string (application);
+      if (app_id == NULL)
+       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;
+    }
 
 
-  value = make_string (*my_handle, rc);
+  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));
 
 
-  HUnlock (my_handle);
+ out:
+  if (app_plist)
+    CFRelease (app_plist);
+  CFRelease (app_id);
 
 
-  DisposeHandle (my_handle);
+  UNBLOCK_INPUT;
 
 
-  return value;
-#endif /* not TARGET_API_MAC_CARBON */
+  return result;
 }
 
 
 }
 
 
-/* set interprogram-cut-function to mac-cut-function in mac-win.el
-   to enable Emacs to write the top of the kill-ring to the Mac clipboard. */
-DEFUN ("mac-cut-function", Fmac_cut_function, Smac_cut_function, 1, 2, 0,
-       doc: /* Put the value of the string parameter to the Mac clipboard.  */)
-  (value, push)
-    Lisp_Object value, push;
+static CFStringEncoding
+get_cfstring_encoding_from_lisp (obj)
+     Lisp_Object obj;
 {
 {
-  char *buf;
-  int len, i;
+  CFStringRef iana_name;
+  CFStringEncoding encoding = kCFStringEncodingInvalidId;
 
 
-  /* fixme: ignore the push flag for now */
+  if (NILP (obj))
+    return kCFStringEncodingUnicode;
 
 
-  CHECK_STRING (value);
+  if (INTEGERP (obj))
+    return XINT (obj);
 
 
-  len = SCHARS (value);
-  buf = (char *) alloca (len+1);
-  bcopy (SDATA (value), buf, len);
-  buf[len] = '\0';
-
-  /* convert to Mac-style eol's before sending to clipboard */
-  for (i = 0; i < len; i++)
-    if (buf[i] == '\n')
-      buf[i] = '\r';
+  if (SYMBOLP (obj) && !NILP (Fcoding_system_p (obj)))
+    {
+      Lisp_Object coding_spec, plist;
 
 
-#if TARGET_API_MAC_CARBON
-  {
-    ScrapRef scrap;
+      coding_spec = Fget (obj, Qcoding_system);
+      plist = XVECTOR (coding_spec)->contents[3];
+      obj = Fplist_get (XVECTOR (coding_spec)->contents[3], Qmime_charset);
+    }
 
 
-    BLOCK_INPUT;
-    ClearCurrentScrap ();
-    if (GetCurrentScrap (&scrap) != noErr)
-      {
-       UNBLOCK_INPUT;
-       error ("cannot get current scrap");
-      }
+  if (SYMBOLP (obj))
+    obj = SYMBOL_NAME (obj);
 
 
-    if (PutScrapFlavor (scrap, kScrapFlavorTypeText, kScrapFlavorMaskNone, len,
-                       buf) != noErr)
-      {
-       UNBLOCK_INPUT;
-       error ("cannot put to scrap");
-      }
-    UNBLOCK_INPUT;
-  }
-#else /* not TARGET_API_MAC_CARBON */
-  ZeroScrap ();
-  PutScrap (len, 'TEXT', buf);
-#endif /* not TARGET_API_MAC_CARBON */
+  if (STRINGP (obj))
+    {
+      iana_name = cfstring_create_with_string (obj);
+      if (iana_name)
+       {
+         encoding = CFStringConvertIANACharSetNameToEncoding (iana_name);
+         CFRelease (iana_name);
+       }
+    }
 
 
-  return Qnil;
+  return encoding;
 }
 
 }
 
-
-DEFUN ("x-selection-exists-p", Fx_selection_exists_p, Sx_selection_exists_p,
-       0, 1, 0,
-       doc: /* Whether there is an owner for the given X Selection.
-The arg should be the name of the selection in question, typically one of
-the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.
-\(Those are literal upper-case symbol names, since that's what X expects.)
-For convenience, the symbol nil is the same as `PRIMARY',
-and t is the same as `SECONDARY'.  */)
-  (selection)
-     Lisp_Object selection;
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
+static CFStringRef
+cfstring_create_normalized (str, symbol)
+     CFStringRef str;
+     Lisp_Object symbol;
 {
 {
-  CHECK_SYMBOL (selection);
+  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;
+    }
 
 
-  /* Return nil for PRIMARY and SECONDARY selections; for CLIPBOARD, check
-     if the clipboard currently has valid text format contents. */
+  if (form >= 0)
+    {
+      CFMutableStringRef mut_str = CFStringCreateMutableCopy (NULL, 0, str);
 
 
-  if (EQ (selection, QCLIPBOARD))
+      if (mut_str)
+       {
+         CFStringNormalize (mut_str, form);
+         result = mut_str;
+       }
+    }
+  else if (initial_mag > 0.0)
     {
     {
-      Lisp_Object val = Qnil;
+      UnicodeToTextInfo uni = NULL;
+      UnicodeMapping map;
+      CFIndex length;
+      UniChar *in_text, *buffer = NULL, *out_buf = NULL;
+      OSErr 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);
+         if (buffer)
+           {
+             CFStringGetCharacters (str, CFRangeMake (0, length), buffer);
+             in_text = buffer;
+           }
+       }
 
 
-#if TARGET_API_MAC_CARBON
-      ScrapRef scrap;
-      ScrapFlavorFlags sff;
+      if (in_text)
+       err = CreateUnicodeToTextInfo(&map, &uni);
+      while (err == noErr)
+       {
+         out_buf = xmalloc (out_size);
+         if (out_buf == NULL)
+           err = mFulErr;
+         else
+           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);
+    }
 
 
-      BLOCK_INPUT;
-      if (GetCurrentScrap (&scrap) == noErr)
-        if (GetScrapFlavorFlags (scrap, kScrapFlavorTypeText, &sff) == noErr)
-          val = Qt;
-      UNBLOCK_INPUT;
-#else /* not TARGET_API_MAC_CARBON */
-      Handle my_handle;
-      long rc, scrap_offset;
+  return result;
+}
+#endif
 
 
-      my_handle = NewHandle (0);
+DEFUN ("mac-code-convert-string", Fmac_code_convert_string, Smac_code_convert_string, 3, 4, 0,
+       doc: /* Convert STRING from SOURCE encoding to TARGET encoding.
+The conversion is performed using the converter provided by the system.
+Each encoding is specified by either a coding system symbol, a mime
+charset string, or an integer as a CFStringEncoding value.  Nil for
+encoding means UTF-16 in native byte order, no byte order mark.
+On Mac OS X 10.2 and later, you can do Unicode Normalization by
+specifying the optional argument NORMALIZATION-FORM with a symbol NFD,
+NFKD, NFC, NFKC, HFS+D, or HFS+C.
+On successful conversion, return the result string, else return nil.  */)
+     (string, source, target, normalization_form)
+     Lisp_Object string, source, target, normalization_form;
+{
+  Lisp_Object result = Qnil;
+  CFStringEncoding src_encoding, tgt_encoding;
+  CFStringRef str = NULL;
 
 
-      rc = GetScrap (my_handle, 'TEXT', &scrap_offset);
-      if (rc >= 0)
-        val = Qt;
+  CHECK_STRING (string);
+  if (!INTEGERP (source) && !STRINGP (source))
+    CHECK_SYMBOL (source);
+  if (!INTEGERP (target) && !STRINGP (target))
+    CHECK_SYMBOL (target);
+  CHECK_SYMBOL (normalization_form);
 
 
-      DisposeHandle (my_handle);
-#endif /* not TARGET_API_MAC_CARBON */
+  BLOCK_INPUT;
 
 
-      return val;
+  src_encoding = get_cfstring_encoding_from_lisp (source);
+  tgt_encoding = get_cfstring_encoding_from_lisp (target);
+
+  /* We really want string_to_unibyte, but since it doesn't exist yet, we
+     use string_as_unibyte which works as well, except for the fact that
+     it's too permissive (it doesn't check that the multibyte string only
+     contain single-byte chars).  */
+  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);
     }
     }
-  return Qnil;
+#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;
+
+  return result;
 }
 }
+#endif /* TARGET_API_MAC_CARBON */
 
 
-extern void mac_clear_font_name_table P_ ((void));
 
 DEFUN ("mac-clear-font-name-table", Fmac_clear_font_name_table, Smac_clear_font_name_table, 0, 0, 0,
        doc: /* Clear the font name table.  */)
 
 DEFUN ("mac-clear-font-name-table", Fmac_clear_font_name_table, Smac_clear_font_name_table, 0, 0, 0,
        doc: /* Clear the font name table.  */)
-  ()
+     ()
 {
   check_mac ();
   mac_clear_font_name_table ();
   return Qnil;
 }
 
 {
   check_mac ();
   mac_clear_font_name_table ();
   return Qnil;
 }
 
+
+static Lisp_Object
+mac_get_system_locale ()
+{
+  OSErr err;
+  LangCode lang;
+  RegionCode region;
+  LocaleRef locale;
+  Str255 str;
+
+  lang = GetScriptVariable (smSystemScript, smScriptLang);
+  region = GetScriptManagerVariable (smRegionCode);
+  err = LocaleRefFromLangOrRegionCode (lang, region, &locale);
+  if (err == noErr)
+    err = LocaleRefGetPartString (locale, kLocaleAllPartsMask,
+                                 sizeof (str), str);
+  if (err == noErr)
+    return build_string (str);
+  else
+    return Qnil;
+}
+
+
 #ifdef MAC_OSX
 #undef select
 
 #ifdef MAC_OSX
 #undef select
 
@@ -2802,7 +4762,7 @@ extern int noninteractive;
       involved, and timeout is not too short (greater than
       SELECT_TIMEOUT_THRESHHOLD_RUNLOOP seconds).
       -> Create CFSocket for each socket and add it into the current
       involved, and timeout is not too short (greater than
       SELECT_TIMEOUT_THRESHHOLD_RUNLOOP seconds).
       -> Create CFSocket for each socket and add it into the current
-         event RunLoop so that an `ready-to-read' event can be posted
+         event RunLoop so that a `ready-to-read' event can be posted
          to the event queue that is also used for window events.  Then
          ReceiveNextEvent can wait for both kinds of inputs.
    4. Otherwise.
          to the event queue that is also used for window events.  Then
          ReceiveNextEvent can wait for both kinds of inputs.
    4. Otherwise.
@@ -2858,7 +4818,7 @@ select_and_poll_event (n, rfds, wfds, efds, timeout)
   return r;
 }
 
   return r;
 }
 
-#ifndef MAC_OS_X_VERSION_10_2
+#if MAC_OS_X_VERSION_MAX_ALLOWED < 1020
 #undef SELECT_INVALIDATE_CFSOCKET
 #endif
 
 #undef SELECT_INVALIDATE_CFSOCKET
 #endif
 
@@ -3070,12 +5030,22 @@ init_mac_osx_environment ()
   char *p, *q;
   struct stat st;
 
   char *p, *q;
   struct stat st;
 
+  /* Initialize locale related variables.  */
+  mac_system_script_code =
+    (ScriptCode) GetScriptManagerVariable (smSysScript);
+  Vmac_system_locale = mac_get_system_locale ();
+
   /* Fetch the pathname of the application bundle as a C string into
      app_bundle_pathname.  */
 
   bundle = CFBundleGetMainBundle ();
   /* Fetch the pathname of the application bundle as a C string into
      app_bundle_pathname.  */
 
   bundle = CFBundleGetMainBundle ();
-  if (!bundle)
-    return;
+  if (!bundle || CFBundleGetIdentifier (bundle) == NULL)
+    {
+      /* We could not find the bundle identifier.  For now, prevent
+        the fatal error by bringing it up in the terminal. */
+      inhibit_window_system = 1;
+      return;
+    }
 
   bundleURL = CFBundleCopyBundleURL (bundle);
   if (!bundleURL)
 
   bundleURL = CFBundleCopyBundleURL (bundle);
   if (!bundleURL)
@@ -3183,20 +5153,60 @@ init_mac_osx_environment ()
 }
 #endif /* MAC_OSX */
 
 }
 #endif /* MAC_OSX */
 
+
 void
 syms_of_mac ()
 {
 void
 syms_of_mac ()
 {
-  QCLIPBOARD = intern ("CLIPBOARD");
-  staticpro (&QCLIPBOARD);
+  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
 
 
-  defsubr (&Smac_paste_function);
-  defsubr (&Smac_cut_function);
-  defsubr (&Sx_selection_exists_p);
+  defsubr (&Smac_coerce_ae_data);
+#if TARGET_API_MAC_CARBON
+  defsubr (&Smac_get_preference);
+  defsubr (&Smac_code_convert_string);
+#endif
   defsubr (&Smac_clear_font_name_table);
 
   defsubr (&Smac_clear_font_name_table);
 
+  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);
   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: /* The system script code.  */);
+  mac_system_script_code = (ScriptCode) GetScriptManagerVariable (smSysScript);
+
+  DEFVAR_LISP ("mac-system-locale", &Vmac_system_locale,
+    doc: /* The system locale identifier string.
+This is not a POSIX locale ID, but an ICU locale ID.  So encoding
+information is not included.  */);
+  Vmac_system_locale = mac_get_system_locale ();
 }
 
 /* arch-tag: 29d30c1f-0c6b-4f88-8a6d-0558d7f9dbff
 }
 
 /* arch-tag: 29d30c1f-0c6b-4f88-8a6d-0558d7f9dbff