summaryrefslogtreecommitdiff
path: root/src/mac.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mac.c')
-rw-r--r--src/mac.c2758
1 files changed, 2758 insertions, 0 deletions
diff --git a/src/mac.c b/src/mac.c
new file mode 100644
index 00000000000..4e6ee4bb8ff
--- /dev/null
+++ b/src/mac.c
@@ -0,0 +1,2758 @@
+/* Unix emulation routines for GNU Emacs on the Mac OS.
+ Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+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
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* Contributed by Andrew Choi (akochoi@mac.com). */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <utime.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <pwd.h>
+#include <sys/param.h>
+#if __MWERKS__
+#include <unistd.h>
+#endif
+
+#ifdef MAC_OSX
+#undef mktime
+#undef DEBUG
+#undef free
+#undef malloc
+#undef realloc
+#include <Carbon/Carbon.h>
+#undef free
+#define free unexec_free
+#undef malloc
+#define malloc unexec_malloc
+#undef realloc
+#define realloc unexec_realloc
+#else /* not MAC_OSX */
+#include <Files.h>
+#include <MacTypes.h>
+#include <TextUtils.h>
+#include <Folders.h>
+#include <Resources.h>
+#include <Aliases.h>
+#include <FixMath.h>
+#include <Timer.h>
+#include <OSA.h>
+#include <AppleScript.h>
+#include <Scrap.h>
+#endif /* not MAC_OSX */
+
+#include "lisp.h"
+#include "process.h"
+#include "sysselect.h"
+#include "systime.h"
+
+Lisp_Object QCLIPBOARD;
+
+/* 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;
+
+
+/* When converting from Mac to Unix pathnames, /'s in folder names are
+ converted to :'s. This function, used in copying folder names,
+ performs a strncat and converts all character a to b in the copy of
+ the string s2 appended to the end of s1. */
+
+void
+string_cat_and_replace (char *s1, const char *s2, int n, char a, char b)
+{
+ int l1 = strlen (s1);
+ int l2 = strlen (s2);
+ char *p = s1 + l1;
+ int i;
+
+ strncat (s1, s2, n);
+ for (i = 0; i < l2; i++)
+ {
+ if (*p == a)
+ *p = b;
+ p++;
+ }
+}
+
+
+/* Convert a Mac pathname to Posix form. A Mac full pathname is one
+ that does not begin with a ':' and contains at least one ':'. A Mac
+ full pathname causes an '/' to be prepended to the Posix pathname.
+ The algorithm for the rest of the pathname is as follows:
+ For each segment between two ':',
+ if it is non-null, copy as is and then add a '/' at the end,
+ otherwise, insert a "../" into the Posix pathname.
+ Returns 1 if successful; 0 if fails. */
+
+int
+mac_to_posix_pathname (const char *mfn, char *ufn, int ufnbuflen)
+{
+ const char *p, *q, *pe;
+
+ strcpy (ufn, "");
+
+ if (*mfn == '\0')
+ return 1;
+
+ p = strchr (mfn, ':');
+ if (p != 0 && p != mfn) /* full pathname */
+ strcat (ufn, "/");
+
+ p = mfn;
+ if (*p == ':')
+ p++;
+
+ 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;
+}
+
+#ifndef MAC_OSX
+
+/* The following functions with "sys_" prefix are stubs to Unix
+ functions that have already been implemented by CW or MPW. The
+ calls to them in Emacs source course are #define'd to call the sys_
+ versions by the header files s-mac.h. In these stubs pathnames are
+ converted between their Unix and Mac forms. */
+
+
+/* Unix epoch is Jan 1, 1970 while Mac epoch is Jan 1, 1904: 66 years
+ + 17 leap days. These are for adjusting time values returned by
+ MacOS Toolbox functions. */
+
+#define MAC_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
+
+#ifdef __MWERKS__
+#if __MSL__ < 0x6000
+/* CW Pro 5 epoch is Jan 1, 1900 (aaarghhhhh!); remember, 1900 is not
+ a leap year! This is for adjusting time_t values returned by MSL
+ functions. */
+#define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 70 + 17) * 24 * 60 * 60)
+#else /* __MSL__ >= 0x6000 */
+/* CW changes Pro 6 to follow Unix! */
+#define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
+#endif /* __MSL__ >= 0x6000 */
+#elif __MRC__
+/* MPW library functions follow Unix (confused?). */
+#define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
+#else /* not __MRC__ */
+You lose!!!
+#endif /* not __MRC__ */
+
+
+/* Define our own stat function for both MrC and CW. The reason for
+ doing this: "stat" is both the name of a struct and function name:
+ can't use the same trick like that for sys_open, sys_close, etc. to
+ redirect Emacs's calls to our own version that converts Unix style
+ filenames to Mac style filename because all sorts of compilation
+ errors will be generated if stat is #define'd to be sys_stat. */
+
+int
+stat_noalias (const char *path, struct stat *buf)
+{
+ char mac_pathname[MAXPATHLEN+1];
+ CInfoPBRec cipb;
+
+ if (posix_to_mac_pathname (path, mac_pathname, MAXPATHLEN+1) == 0)
+ return -1;
+
+ c2pstr (mac_pathname);
+ cipb.hFileInfo.ioNamePtr = mac_pathname;
+ cipb.hFileInfo.ioVRefNum = 0;
+ cipb.hFileInfo.ioDirID = 0;
+ cipb.hFileInfo.ioFDirIndex = 0;
+ /* set to 0 to get information about specific dir or file */
+
+ errno = PBGetCatInfo (&cipb, false);
+ if (errno == -43) /* -43: fnfErr defined in Errors.h */
+ errno = ENOENT;
+ if (errno != noErr)
+ return -1;
+
+ if (cipb.hFileInfo.ioFlAttrib & 0x10) /* bit 4 = 1 for directories */
+ {
+ buf->st_mode = S_IFDIR | S_IREAD | S_IEXEC;
+
+ if (!(cipb.hFileInfo.ioFlAttrib & 0x1))
+ buf->st_mode |= S_IWRITE; /* bit 1 = 1 for locked files/directories */
+ buf->st_ino = cipb.dirInfo.ioDrDirID;
+ buf->st_dev = cipb.dirInfo.ioVRefNum;
+ buf->st_size = cipb.dirInfo.ioDrNmFls;
+ /* size of dir = number of files and dirs */
+ buf->st_atime
+ = buf->st_mtime
+ = cipb.dirInfo.ioDrMdDat - MAC_UNIX_EPOCH_DIFF;
+ buf->st_ctime = cipb.dirInfo.ioDrCrDat - MAC_UNIX_EPOCH_DIFF;
+ }
+ else
+ {
+ buf->st_mode = S_IFREG | S_IREAD;
+ if (!(cipb.hFileInfo.ioFlAttrib & 0x1))
+ buf->st_mode |= S_IWRITE; /* bit 1 = 1 for locked files/directories */
+ if (cipb.hFileInfo.ioFlFndrInfo.fdType == 'APPL')
+ buf->st_mode |= S_IEXEC;
+ buf->st_ino = cipb.hFileInfo.ioDirID;
+ buf->st_dev = cipb.hFileInfo.ioVRefNum;
+ buf->st_size = cipb.hFileInfo.ioFlLgLen;
+ buf->st_atime
+ = buf->st_mtime
+ = cipb.hFileInfo.ioFlMdDat - MAC_UNIX_EPOCH_DIFF;
+ buf->st_ctime = cipb.hFileInfo.ioFlCrDat - MAC_UNIX_EPOCH_DIFF;
+ }
+
+ if (cipb.hFileInfo.ioFlFndrInfo.fdFlags & 0x8000)
+ {
+ /* identify alias files as symlinks */
+ buf->st_mode &= ~S_IFREG;
+ buf->st_mode |= S_IFLNK;
+ }
+
+ buf->st_nlink = 1;
+ buf->st_uid = getuid ();
+ buf->st_gid = getgid ();
+ buf->st_rdev = 0;
+
+ return 0;
+}
+
+
+int
+lstat (const char *path, struct stat *buf)
+{
+ int result;
+ char true_pathname[MAXPATHLEN+1];
+
+ /* Try looking for the file without resolving aliases first. */
+ if ((result = stat_noalias (path, buf)) >= 0)
+ return result;
+
+ if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
+ return -1;
+
+ return stat_noalias (true_pathname, buf);
+}
+
+
+int
+stat (const char *path, struct stat *sb)
+{
+ int result;
+ char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
+ int len;
+
+ if ((result = stat_noalias (path, sb)) >= 0 &&
+ ! (sb->st_mode & S_IFLNK))
+ return result;
+
+ if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
+ return -1;
+
+ len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
+ if (len > -1)
+ {
+ fully_resolved_name[len] = '\0';
+ /* in fact our readlink terminates strings */
+ return lstat (fully_resolved_name, sb);
+ }
+ else
+ return lstat (true_pathname, sb);
+}
+
+
+#if __MRC__
+/* CW defines fstat in stat.mac.c while MPW does not provide this
+ function. Without the information of how to get from a file
+ descriptor in MPW StdCLib to a Mac OS file spec, it should be hard
+ to implement this function. Fortunately, there is only one place
+ where this function is called in our configuration: in fileio.c,
+ where only the st_dev and st_ino fields are used to determine
+ whether two fildes point to different i-nodes to prevent copying
+ a file onto itself equal. What we have here probably needs
+ improvement. */
+
+int
+fstat (int fildes, struct stat *buf)
+{
+ buf->st_dev = 0;
+ buf->st_ino = fildes;
+ buf->st_mode = S_IFREG; /* added by T.I. for the copy-file */
+ return 0; /* success */
+}
+#endif /* __MRC__ */
+
+
+int
+mkdir (const char *dirname, int mode)
+{
+#pragma unused(mode)
+
+ HFileParam hfpb;
+ char true_pathname[MAXPATHLEN+1], mac_pathname[MAXPATHLEN+1];
+
+ if (find_true_pathname (dirname, true_pathname, MAXPATHLEN+1) == -1)
+ return -1;
+
+ if (posix_to_mac_pathname (true_pathname, mac_pathname, MAXPATHLEN+1) == 0)
+ return -1;
+
+ c2pstr (mac_pathname);
+ hfpb.ioNamePtr = mac_pathname;
+ hfpb.ioVRefNum = 0; /* ignored unless name is invalid */
+ hfpb.ioDirID = 0; /* parent is the root */
+
+ errno = PBDirCreate ((HParmBlkPtr) &hfpb, false);
+ /* just return the Mac OSErr code for now */
+ return errno == noErr ? 0 : -1;
+}
+
+
+#undef rmdir
+sys_rmdir (const char *dirname)
+{
+ HFileParam hfpb;
+ char mac_pathname[MAXPATHLEN+1];
+
+ if (posix_to_mac_pathname (dirname, mac_pathname, MAXPATHLEN+1) == 0)
+ return -1;
+
+ c2pstr (mac_pathname);
+ hfpb.ioNamePtr = mac_pathname;
+ hfpb.ioVRefNum = 0; /* ignored unless name is invalid */
+ hfpb.ioDirID = 0; /* parent is the root */
+
+ errno = PBHDelete ((HParmBlkPtr) &hfpb, false);
+ return errno == noErr ? 0 : -1;
+}
+
+
+#ifdef __MRC__
+/* No implementation yet. */
+int
+execvp (const char *path, ...)
+{
+ return -1;
+}
+#endif /* __MRC__ */
+
+
+int
+utime (const char *path, const struct utimbuf *times)
+{
+ char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
+ int len;
+ char mac_pathname[MAXPATHLEN+1];
+ CInfoPBRec cipb;
+
+ if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
+ return -1;
+
+ len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
+ if (len > -1)
+ fully_resolved_name[len] = '\0';
+ else
+ strcpy (fully_resolved_name, true_pathname);
+
+ if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
+ return -1;
+
+ c2pstr (mac_pathname);
+ cipb.hFileInfo.ioNamePtr = mac_pathname;
+ cipb.hFileInfo.ioVRefNum = 0;
+ cipb.hFileInfo.ioDirID = 0;
+ cipb.hFileInfo.ioFDirIndex = 0;
+ /* set to 0 to get information about specific dir or file */
+
+ errno = PBGetCatInfo (&cipb, false);
+ if (errno != noErr)
+ return -1;
+
+ if (cipb.hFileInfo.ioFlAttrib & 0x10) /* bit 4 = 1 for directories */
+ {
+ if (times)
+ cipb.dirInfo.ioDrMdDat = times->modtime + MAC_UNIX_EPOCH_DIFF;
+ else
+ GetDateTime (&cipb.dirInfo.ioDrMdDat);
+ }
+ else
+ {
+ if (times)
+ cipb.hFileInfo.ioFlMdDat = times->modtime + MAC_UNIX_EPOCH_DIFF;
+ else
+ GetDateTime (&cipb.hFileInfo.ioFlMdDat);
+ }
+
+ errno = PBSetCatInfo (&cipb, false);
+ return errno == noErr ? 0 : -1;
+}
+
+
+#ifndef F_OK
+#define F_OK 0
+#endif
+#ifndef X_OK
+#define X_OK 1
+#endif
+#ifndef W_OK
+#define W_OK 2
+#endif
+
+/* Like stat, but test for access mode in hfpb.ioFlAttrib */
+int
+access (const char *path, int mode)
+{
+ char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
+ int len;
+ char mac_pathname[MAXPATHLEN+1];
+ CInfoPBRec cipb;
+
+ if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
+ return -1;
+
+ len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
+ if (len > -1)
+ fully_resolved_name[len] = '\0';
+ else
+ strcpy (fully_resolved_name, true_pathname);
+
+ if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
+ return -1;
+
+ c2pstr (mac_pathname);
+ cipb.hFileInfo.ioNamePtr = mac_pathname;
+ cipb.hFileInfo.ioVRefNum = 0;
+ cipb.hFileInfo.ioDirID = 0;
+ cipb.hFileInfo.ioFDirIndex = 0;
+ /* set to 0 to get information about specific dir or file */
+
+ errno = PBGetCatInfo (&cipb, false);
+ if (errno != noErr)
+ return -1;
+
+ if (mode == F_OK) /* got this far, file exists */
+ return 0;
+
+ if (mode & X_OK)
+ if (cipb.hFileInfo.ioFlAttrib & 0x10) /* path refers to a directory */
+ return 0;
+ else
+ {
+ if (cipb.hFileInfo.ioFlFndrInfo.fdType == 'APPL')
+ return 0;
+ else
+ return -1;
+ }
+
+ if (mode & W_OK)
+ return (cipb.hFileInfo.ioFlAttrib & 0x1) ? -1 : 0;
+ /* don't allow if lock bit is on */
+
+ return -1;
+}
+
+
+#define DEV_NULL_FD 0x10000
+
+#undef open
+int
+sys_open (const char *path, int oflag)
+{
+ char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
+ int len;
+ char mac_pathname[MAXPATHLEN+1];
+
+ if (strcmp (path, "/dev/null") == 0)
+ return DEV_NULL_FD; /* some bogus fd to be ignored in write */
+
+ if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
+ return -1;
+
+ len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
+ if (len > -1)
+ fully_resolved_name[len] = '\0';
+ else
+ strcpy (fully_resolved_name, true_pathname);
+
+ if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
+ return -1;
+ else
+ {
+#ifdef __MRC__
+ int res = open (mac_pathname, oflag);
+ /* if (oflag == O_WRONLY || oflag == O_RDWR) */
+ if (oflag & O_CREAT)
+ fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
+ return res;
+#else /* not __MRC__ */
+ return open (mac_pathname, oflag);
+#endif /* not __MRC__ */
+ }
+}
+
+
+#undef creat
+int
+sys_creat (const char *path, mode_t mode)
+{
+ char true_pathname[MAXPATHLEN+1];
+ int len;
+ char mac_pathname[MAXPATHLEN+1];
+
+ if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
+ return -1;
+
+ if (!posix_to_mac_pathname (true_pathname, mac_pathname, MAXPATHLEN+1))
+ return -1;
+ else
+ {
+#ifdef __MRC__
+ int result = creat (mac_pathname);
+ fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
+ return result;
+#else /* not __MRC__ */
+ return creat (mac_pathname, mode);
+#endif /* not __MRC__ */
+ }
+}
+
+
+#undef unlink
+int
+sys_unlink (const char *path)
+{
+ char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
+ int len;
+ char mac_pathname[MAXPATHLEN+1];
+
+ if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
+ return -1;
+
+ len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
+ if (len > -1)
+ fully_resolved_name[len] = '\0';
+ else
+ strcpy (fully_resolved_name, true_pathname);
+
+ if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
+ return -1;
+ else
+ return unlink (mac_pathname);
+}
+
+
+#undef read
+int
+sys_read (int fildes, char *buf, int count)
+{
+ if (fildes == 0) /* this should not be used for console input */
+ return -1;
+ else
+#if __MSL__ >= 0x6000
+ return _read (fildes, buf, count);
+#else
+ return read (fildes, buf, count);
+#endif
+}
+
+
+#undef write
+int
+sys_write (int fildes, const char *buf, int count)
+{
+ if (fildes == DEV_NULL_FD)
+ return count;
+ else
+#if __MSL__ >= 0x6000
+ return _write (fildes, buf, count);
+#else
+ return write (fildes, buf, count);
+#endif
+}
+
+
+#undef rename
+int
+sys_rename (const char * old_name, const char * new_name)
+{
+ char true_old_pathname[MAXPATHLEN+1], true_new_pathname[MAXPATHLEN+1];
+ char fully_resolved_old_name[MAXPATHLEN+1];
+ int len;
+ char mac_old_name[MAXPATHLEN+1], mac_new_name[MAXPATHLEN+1];
+
+ if (find_true_pathname (old_name, true_old_pathname, MAXPATHLEN+1) == -1)
+ return -1;
+
+ len = readlink (true_old_pathname, fully_resolved_old_name, MAXPATHLEN);
+ if (len > -1)
+ fully_resolved_old_name[len] = '\0';
+ else
+ strcpy (fully_resolved_old_name, true_old_pathname);
+
+ if (find_true_pathname (new_name, true_new_pathname, MAXPATHLEN+1) == -1)
+ return -1;
+
+ if (strcmp (fully_resolved_old_name, true_new_pathname) == 0)
+ return 0;
+
+ if (!posix_to_mac_pathname (fully_resolved_old_name,
+ mac_old_name,
+ MAXPATHLEN+1))
+ return -1;
+
+ if (!posix_to_mac_pathname(true_new_pathname, mac_new_name, MAXPATHLEN+1))
+ return -1;
+
+ /* If a file with new_name already exists, rename deletes the old
+ file in Unix. CW version fails in these situation. So we add a
+ call to unlink here. */
+ (void) unlink (mac_new_name);
+
+ return rename (mac_old_name, mac_new_name);
+}
+
+
+#undef fopen
+extern FILE *fopen (const char *name, const char *mode);
+FILE *
+sys_fopen (const char *name, const char *mode)
+{
+ char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
+ int len;
+ char mac_pathname[MAXPATHLEN+1];
+
+ if (find_true_pathname (name, true_pathname, MAXPATHLEN+1) == -1)
+ return 0;
+
+ len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
+ if (len > -1)
+ fully_resolved_name[len] = '\0';
+ else
+ strcpy (fully_resolved_name, true_pathname);
+
+ if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
+ return 0;
+ else
+ {
+#ifdef __MRC__
+ if (mode[0] == 'w' || mode[0] == 'a')
+ fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
+#endif /* not __MRC__ */
+ return fopen (mac_pathname, mode);
+ }
+}
+
+
+#include <Events.h>
+
+long target_ticks = 0;
+
+#ifdef __MRC__
+__sigfun alarm_signal_func = (__sigfun) 0;
+#elif __MWERKS__
+__signal_func_ptr alarm_signal_func = (__signal_func_ptr) 0;
+#else /* not __MRC__ and not __MWERKS__ */
+You lose!!!
+#endif /* not __MRC__ and not __MWERKS__ */
+
+
+/* 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 ()
+{
+ if (target_ticks && TickCount () > target_ticks)
+ {
+ target_ticks = 0;
+ if (alarm_signal_func)
+ (*alarm_signal_func)(SIGALRM);
+ }
+}
+
+
+int
+select (n, rfds, wfds, efds, timeout)
+ int n;
+ SELECT_TYPE *rfds;
+ SELECT_TYPE *wfds;
+ SELECT_TYPE *efds;
+ struct timeval *timeout;
+{
+#ifdef TARGET_API_MAC_CARBON
+ return 1;
+#else /* not TARGET_API_MAC_CARBON */
+ EMACS_TIME end_time, now;
+ EventRecord e;
+
+ /* Can only handle wait for keyboard input. */
+ if (n > 1 || wfds || efds)
+ return -1;
+
+ EMACS_GET_TIME (end_time);
+ EMACS_ADD_TIME (end_time, end_time, *timeout);
+
+ do
+ {
+ /* 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) && EventAvail (everyEvent, &e))
+ return 1;
+
+ /* Also check movement of the mouse. */
+ {
+ Point mouse_pos;
+ static Point old_mouse_pos = {-1, -1};
+
+ GetMouse (&mouse_pos);
+ if (!EqualPt (mouse_pos, old_mouse_pos))
+ {
+ old_mouse_pos = mouse_pos;
+ return 1;
+ }
+ }
+
+ WaitNextEvent (0, &e, 1UL, NULL); /* Accept no event; wait 1
+ tic. by T.I. */
+
+ EMACS_GET_TIME (now);
+ EMACS_SUB_TIME (now, end_time, now);
+ }
+ while (!EMACS_TIME_NEG_P (now));
+
+ return 0;
+#endif /* not TARGET_API_MAC_CARBON */
+}
+
+
+/* Called in sys_select to wait for an alarm signal to arrive. */
+
+int
+pause ()
+{
+ EventRecord e;
+ unsigned long tick;
+
+ if (!target_ticks) /* no alarm pending */
+ return -1;
+
+ if ((tick = TickCount ()) < target_ticks)
+ WaitNextEvent (0, &e, target_ticks - tick, NULL); /* Accept no event;
+ just wait. by T.I. */
+
+ target_ticks = 0;
+ if (alarm_signal_func)
+ (*alarm_signal_func)(SIGALRM);
+
+ return 0;
+}
+
+
+int
+alarm (int seconds)
+{
+ long remaining = target_ticks ? (TickCount () - target_ticks) / 60 : 0;
+
+ target_ticks = seconds ? TickCount () + 60 * seconds : 0;
+
+ return (remaining < 0) ? 0 : (unsigned int) remaining;
+}
+
+
+#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;
+ }
+}
+
+
+/* gettimeofday should return the amount of time (in a timeval
+ structure) since midnight today. The toolbox function Microseconds
+ returns the number of microseconds (in a UnsignedWide value) since
+ the machine was booted. Also making this complicated is WideAdd,
+ WideSubtract, etc. take wide values. */
+
+int
+gettimeofday (tp)
+ struct timeval *tp;
+{
+ static inited = 0;
+ static wide wall_clock_at_epoch, clicks_at_epoch;
+ UnsignedWide uw_microseconds;
+ wide w_microseconds;
+ time_t sys_time (time_t *);
+
+ /* If this function is called for the first time, record the number
+ of seconds since midnight and the number of microseconds since
+ boot at the time of this first call. */
+ if (!inited)
+ {
+ time_t systime;
+ inited = 1;
+ systime = sys_time (NULL);
+ /* Store microseconds since midnight in wall_clock_at_epoch. */
+ WideMultiply (systime, 1000000L, &wall_clock_at_epoch);
+ Microseconds (&uw_microseconds);
+ /* Store microseconds since boot in clicks_at_epoch. */
+ clicks_at_epoch.hi = uw_microseconds.hi;
+ clicks_at_epoch.lo = uw_microseconds.lo;
+ }
+
+ /* Get time since boot */
+ Microseconds (&uw_microseconds);
+
+ /* Convert to time since midnight*/
+ w_microseconds.hi = uw_microseconds.hi;
+ w_microseconds.lo = uw_microseconds.lo;
+ WideSubtract (&w_microseconds, &clicks_at_epoch);
+ WideAdd (&w_microseconds, &wall_clock_at_epoch);
+ tp->tv_sec = WideDivide (&w_microseconds, 1000000L, &tp->tv_usec);
+
+ return 0;
+}
+
+
+#ifdef __MRC__
+unsigned int
+sleep (unsigned int seconds)
+{
+ unsigned long time_up;
+ EventRecord e;
+
+ time_up = TickCount () + seconds * 60;
+ while (TickCount () < time_up)
+ {
+ /* Accept no event; just wait. by T.I. */
+ WaitNextEvent (0, &e, 30, NULL);
+ }
+
+ return (0);
+}
+#endif /* __MRC__ */
+
+
+/* The time functions adjust time values according to the difference
+ between the Unix and CW epoches. */
+
+#undef gmtime
+extern struct tm *gmtime (const time_t *);
+struct tm *
+sys_gmtime (const time_t *timer)
+{
+ time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
+
+ return gmtime (&unix_time);
+}
+
+
+#undef localtime
+extern struct tm *localtime (const time_t *);
+struct tm *
+sys_localtime (const time_t *timer)
+{
+#if __MSL__ >= 0x6000
+ time_t unix_time = *timer;
+#else
+ time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
+#endif
+
+ return localtime (&unix_time);
+}
+
+
+#undef ctime
+extern char *ctime (const time_t *);
+char *
+sys_ctime (const time_t *timer)
+{
+#if __MSL__ >= 0x6000
+ time_t unix_time = *timer;
+#else
+ time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
+#endif
+
+ return ctime (&unix_time);
+}
+
+
+#undef time
+extern time_t time (time_t *);
+time_t
+sys_time (time_t *timer)
+{
+#if __MSL__ >= 0x6000
+ time_t mac_time = time (NULL);
+#else
+ time_t mac_time = time (NULL) - CW_OR_MPW_UNIX_EPOCH_DIFF;
+#endif
+
+ if (timer)
+ *timer = mac_time;
+
+ return mac_time;
+}
+
+
+/* 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
+wait (int pid)
+{
+ return 0;
+}
+
+
+void
+croak (char *badfunc)
+{
+ printf ("%s not yet implemented\r\n", badfunc);
+ exit (1);
+}
+
+
+char *
+index (const char * str, int chr)
+{
+ return strchr (str, chr);
+}
+
+
+char *
+mktemp (char *template)
+{
+ int len, k;
+ static seqnum = 0;
+
+ len = strlen (template);
+ k = len - 1;
+ while (k >= 0 && template[k] == 'X')
+ k--;
+
+ k++; /* make k index of first 'X' */
+
+ if (k < len)
+ {
+ /* Zero filled, number of digits equal to the number of X's. */
+ sprintf (&template[k], "%0*d", len-k, seqnum++);
+
+ return template;
+ }
+ else
+ return 0;
+}
+
+
+/* Emulate getpwuid, getpwnam and others. */
+
+#define PASSWD_FIELD_SIZE 256
+
+static char my_passwd_name[PASSWD_FIELD_SIZE];
+static char my_passwd_dir[MAXPATHLEN+1];
+
+static struct passwd my_passwd =
+{
+ my_passwd_name,
+ my_passwd_dir,
+};
+
+
+/* Initialized by main () in macterm.c to pathname of emacs directory. */
+
+char emacs_passwd_dir[MAXPATHLEN+1];
+
+char *
+getwd (char *);
+
+void
+init_emacs_passwd_dir ()
+{
+ int found = false;
+
+ if (getwd (emacs_passwd_dir) && getwd (my_passwd_dir))
+ {
+ /* Need pathname of first ancestor that begins with "emacs"
+ since Mac emacs application is somewhere in the emacs-*
+ tree. */
+ int len = strlen (emacs_passwd_dir);
+ int j = len - 1;
+ /* j points to the "/" following the directory name being
+ compared. */
+ int i = j - 1;
+ while (i >= 0 && !found)
+ {
+ while (i >= 0 && emacs_passwd_dir[i] != '/')
+ i--;
+ if (emacs_passwd_dir[i] == '/' && i+5 < len)
+ found = (strncmp (&(emacs_passwd_dir[i+1]), "emacs", 5) == 0);
+ if (found)
+ emacs_passwd_dir[j+1] = '\0';
+ else
+ {
+ j = i;
+ i = j - 1;
+ }
+ }
+ }
+
+ if (!found)
+ {
+ /* Setting to "/" probably won't work but set it to something
+ anyway. */
+ strcpy (emacs_passwd_dir, "/");
+ strcpy (my_passwd_dir, "/");
+ }
+}
+
+
+static struct passwd emacs_passwd =
+{
+ "emacs",
+ emacs_passwd_dir,
+};
+
+static int my_passwd_inited = 0;
+
+
+static void
+init_my_passwd ()
+{
+ char **owner_name;
+
+ /* Note: my_passwd_dir initialized in int_emacs_passwd_dir to
+ directory where Emacs was started. */
+
+ owner_name = (char **) GetResource ('STR ',-16096);
+ if (owner_name)
+ {
+ HLock (owner_name);
+ BlockMove ((unsigned char *) *owner_name,
+ (unsigned char *) my_passwd_name,
+ *owner_name[0]+1);
+ HUnlock (owner_name);
+ p2cstr ((unsigned char *) my_passwd_name);
+ }
+ else
+ my_passwd_name[0] = 0;
+}
+
+
+struct passwd *
+getpwuid (uid_t uid)
+{
+ if (!my_passwd_inited)
+ {
+ init_my_passwd ();
+ my_passwd_inited = 1;
+ }
+
+ return &my_passwd;
+}
+
+
+struct passwd *
+getpwnam (const char *name)
+{
+ if (strcmp (name, "emacs") == 0)
+ return &emacs_passwd;
+
+ if (!my_passwd_inited)
+ {
+ init_my_passwd ();
+ my_passwd_inited = 1;
+ }
+
+ return &my_passwd;
+}
+
+
+/* The functions fork, kill, sigsetmask, sigblock, request_sigio,
+ setpgrp, setpriority, and unrequest_sigio are defined to be empty
+ as in msdos.c. */
+
+
+int
+fork ()
+{
+ return -1;
+}
+
+
+int
+kill (int x, int y)
+{
+ return -1;
+}
+
+
+void
+sys_subshell ()
+{
+ error ("Can't spawn subshell");
+}
+
+
+int
+sigsetmask (int x)
+{
+ return 0;
+}
+
+
+int
+sigblock (int mask)
+{
+ return 0;
+}
+
+
+void
+request_sigio (void)
+{
+}
+
+
+void
+unrequest_sigio (void)
+{
+}
+
+
+int
+setpgrp ()
+{
+ return 0;
+}
+
+
+/* No pipes yet. */
+
+int
+pipe (int _fildes[2])
+{
+ errno = EACCES;
+ return -1;
+}
+
+
+/* Hard and symbolic links. */
+
+int
+symlink (const char *name1, const char *name2)
+{
+ errno = ENOENT;
+ return -1;
+}
+
+
+int
+link (const char *name1, const char *name2)
+{
+ errno = ENOENT;
+ return -1;
+}
+
+#endif /* ! MAC_OSX */
+
+/* Determine the path name of the file specified by VREFNUM, DIRID,
+ and NAME and place that in the buffer PATH of length
+ MAXPATHLEN. */
+int
+path_from_vol_dir_name (char *path, int man_path_len, short vol_ref_num,
+ long dir_id, ConstStr255Param name)
+{
+ Str255 dir_name;
+ CInfoPBRec cipb;
+ OSErr err;
+
+ if (strlen (name) > man_path_len)
+ return 0;
+
+ memcpy (dir_name, name, name[0]+1);
+ memcpy (path, name, name[0]+1);
+ p2cstr (path);
+
+ cipb.dirInfo.ioDrParID = dir_id;
+ cipb.dirInfo.ioNamePtr = dir_name;
+
+ do
+ {
+ cipb.dirInfo.ioVRefNum = vol_ref_num;
+ cipb.dirInfo.ioFDirIndex = -1;
+ cipb.dirInfo.ioDrDirID = cipb.dirInfo.ioDrParID;
+ /* go up to parent each time */
+
+ err = PBGetCatInfo (&cipb, false);
+ if (err != noErr)
+ return 0;
+
+ p2cstr (dir_name);
+ if (strlen (dir_name) + strlen (path) + 1 >= man_path_len)
+ return 0;
+
+ strcat (dir_name, ":");
+ strcat (dir_name, path);
+ /* attach to front since we're going up directory tree */
+ strcpy (path, dir_name);
+ }
+ while (cipb.dirInfo.ioDrDirID != fsRtDirID);
+ /* stop when we see the volume's root directory */
+
+ return 1; /* success */
+}
+
+#ifndef MAC_OSX
+
+int
+readlink (const char *path, char *buf, int bufsiz)
+{
+ char mac_sym_link_name[MAXPATHLEN+1];
+ OSErr err;
+ FSSpec fsspec;
+ Boolean target_is_folder, was_aliased;
+ Str255 directory_name, mac_pathname;
+ CInfoPBRec cipb;
+
+ if (posix_to_mac_pathname (path, mac_sym_link_name, MAXPATHLEN+1) == 0)
+ return -1;
+
+ c2pstr (mac_sym_link_name);
+ err = FSMakeFSSpec (0, 0, mac_sym_link_name, &fsspec);
+ if (err != noErr)
+ {
+ errno = ENOENT;
+ return -1;
+ }
+
+ err = ResolveAliasFile (&fsspec, true, &target_is_folder, &was_aliased);
+ if (err != noErr || !was_aliased)
+ {
+ errno = ENOENT;
+ return -1;
+ }
+
+ if (path_from_vol_dir_name (mac_pathname, 255, fsspec.vRefNum, fsspec.parID,
+ fsspec.name) == 0)
+ {
+ errno = ENOENT;
+ return -1;
+ }
+
+ if (mac_to_posix_pathname (mac_pathname, buf, bufsiz) == 0)
+ {
+ errno = ENOENT;
+ return -1;
+ }
+
+ return strlen (buf);
+}
+
+
+/* Convert a path to one with aliases fully expanded. */
+
+static int
+find_true_pathname (const char *path, char *buf, int bufsiz)
+{
+ char *q, temp[MAXPATHLEN+1];
+ const char *p;
+ int len;
+
+ if (bufsiz <= 0 || path == 0 || path[0] == '\0')
+ return -1;
+
+ buf[0] = '\0';
+
+ p = path;
+ if (*p == '/')
+ q = strchr (p + 1, '/');
+ else
+ q = strchr (p, '/');
+ len = 0; /* loop may not be entered, e.g., for "/" */
+
+ while (q)
+ {
+ strcpy (temp, buf);
+ strncat (temp, p, q - p);
+ len = readlink (temp, buf, bufsiz);
+ if (len <= -1)
+ {
+ if (strlen (temp) + 1 > bufsiz)
+ return -1;
+ strcpy (buf, temp);
+ }
+ strcat (buf, "/");
+ len++;
+ p = q + 1;
+ q = strchr(p, '/');
+ }
+
+ if (len + strlen (p) + 1 >= bufsiz)
+ return -1;
+
+ strcat (buf, p);
+ return len + strlen (p);
+}
+
+
+mode_t
+umask (mode_t numask)
+{
+ static mode_t mask = 022;
+ mode_t oldmask = mask;
+ mask = numask;
+ return oldmask;
+}
+
+
+int
+chmod (const char *path, mode_t mode)
+{
+ /* say it always succeed for now */
+ return 0;
+}
+
+
+int
+dup (int oldd)
+{
+#ifdef __MRC__
+ return fcntl (oldd, F_DUPFD, 0);
+#elif __MWERKS__
+ /* current implementation of fcntl in fcntl.mac.c simply returns old
+ descriptor */
+ return fcntl (oldd, F_DUPFD);
+#else
+You lose!!!
+#endif
+}
+
+
+/* This is from the original sysdep.c. Emulate BSD dup2. First close
+ newd if it already exists. Then, attempt to dup oldd. If not
+ successful, call dup2 recursively until we are, then close the
+ unsuccessful ones. */
+
+int
+dup2 (int oldd, int newd)
+{
+ int fd, ret;
+
+ close (newd);
+
+ fd = dup (oldd);
+ if (fd == -1)
+ return -1;
+ if (fd == newd)
+ return newd;
+ ret = dup2 (oldd, newd);
+ close (fd);
+ return ret;
+}
+
+
+/* let it fail for now */
+
+char *
+sbrk (int incr)
+{
+ return (char *) -1;
+}
+
+
+int
+fsync (int fd)
+{
+ return 0;
+}
+
+
+int
+ioctl (int d, int request, void *argp)
+{
+ return -1;
+}
+
+
+#ifdef __MRC__
+int
+isatty (int fildes)
+{
+ if (fildes >=0 && fildes <= 2)
+ return 1;
+ else
+ return 0;
+}
+
+
+int
+getgid ()
+{
+ return 100;
+}
+
+
+int
+getegid ()
+{
+ return 100;
+}
+
+
+int
+getuid ()
+{
+ return 200;
+}
+
+
+int
+geteuid ()
+{
+ return 200;
+}
+#endif /* __MRC__ */
+
+
+#ifdef __MWERKS__
+#if __MSL__ < 0x6000
+#undef getpid
+int
+getpid ()
+{
+ return 9999;
+}
+#endif
+#endif /* __MWERKS__ */
+
+#endif /* ! MAC_OSX */
+
+
+/* Return the path to the directory in which Emacs can create
+ temporary files. The MacOS "temporary items" directory cannot be
+ used because it removes the file written by a process when it
+ exits. In that sense it's more like "/dev/null" than "/tmp" (but
+ again not exactly). And of course Emacs needs to read back the
+ files written by its subprocesses. So here we write the files to a
+ directory "Emacs" in the Preferences Folder. This directory is
+ created if it does not exist. */
+
+char *
+get_temp_dir_name ()
+{
+ static char *temp_dir_name = NULL;
+ short vol_ref_num;
+ long dir_id;
+ OSErr err;
+ Str255 dir_name, full_path;
+ CInfoPBRec cpb;
+ char unix_dir_name[MAXPATHLEN+1];
+ DIR *dir;
+
+ /* Cache directory name with pointer temp_dir_name.
+ Look for it only the first time. */
+ if (!temp_dir_name)
+ {
+ err = FindFolder (kOnSystemDisk, kPreferencesFolderType, kCreateFolder,
+ &vol_ref_num, &dir_id);
+ if (err != noErr)
+ return NULL;
+
+ if (!path_from_vol_dir_name (full_path, 255, vol_ref_num, dir_id, "\p"))
+ return NULL;
+
+ if (strlen (full_path) + 6 <= MAXPATHLEN)
+ strcat (full_path, "Emacs:");
+ else
+ return NULL;
+
+ if (!mac_to_posix_pathname (full_path, unix_dir_name, MAXPATHLEN+1))
+ return NULL;
+
+ dir = opendir (unix_dir_name); /* check whether temp directory exists */
+ if (dir)
+ closedir (dir);
+ else if (mkdir (unix_dir_name, 0700) != 0) /* create it if not */
+ return NULL;
+
+ temp_dir_name = (char *) malloc (strlen (unix_dir_name) + 1);
+ strcpy (temp_dir_name, unix_dir_name);
+ }
+
+ return temp_dir_name;
+}
+
+#ifndef MAC_OSX
+
+/* Allocate and construct an array of pointers to strings from a list
+ of strings stored in a 'STR#' resource. The returned pointer array
+ is stored in the style of argv and environ: if the 'STR#' resource
+ contains numString strings, an pointer array with numString+1
+ elements is returned in which the last entry contains a null
+ pointer. The pointer to the pointer array is passed by pointer in
+ parameter t. The resource ID of the 'STR#' resource is passed in
+ parameter StringListID.
+ */
+
+void
+get_string_list (char ***t, short string_list_id)
+{
+ Handle h;
+ Ptr p;
+ int i, num_strings;
+
+ h = GetResource ('STR#', string_list_id);
+ if (h)
+ {
+ HLock (h);
+ p = *h;
+ num_strings = * (short *) p;
+ p += sizeof(short);
+ *t = (char **) malloc (sizeof (char *) * (num_strings + 1));
+ for (i = 0; i < num_strings; i++)
+ {
+ short length = *p++;
+ (*t)[i] = (char *) malloc (length + 1);
+ strncpy ((*t)[i], p, length);
+ (*t)[i][length] = '\0';
+ p += length;
+ }
+ (*t)[num_strings] = 0;
+ HUnlock (h);
+ }
+ else
+ {
+ /* Return no string in case GetResource fails. Bug fixed by
+ Ikegami Tsutomu. Caused MPW build to crash without sym -on
+ option (no sym -on implies -opt local). */
+ *t = (char **) malloc (sizeof (char *));
+ (*t)[0] = 0;
+ }
+}
+
+
+static char *
+get_path_to_system_folder ()
+{
+ short vol_ref_num;
+ long dir_id;
+ OSErr err;
+ Str255 dir_name, full_path;
+ CInfoPBRec cpb;
+ static char system_folder_unix_name[MAXPATHLEN+1];
+ DIR *dir;
+
+ err = FindFolder (kOnSystemDisk, kSystemFolderType, kDontCreateFolder,
+ &vol_ref_num, &dir_id);
+ if (err != noErr)
+ return NULL;
+
+ if (!path_from_vol_dir_name (full_path, 255, vol_ref_num, dir_id, "\p"))
+ return NULL;
+
+ if (!mac_to_posix_pathname (full_path, system_folder_unix_name,
+ MAXPATHLEN+1))
+ return NULL;
+
+ return system_folder_unix_name;
+}
+
+
+char **environ;
+
+#define ENVIRON_STRING_LIST_ID 128
+
+/* Get environment variable definitions from STR# resource. */
+
+void
+init_environ ()
+{
+ int i;
+
+ get_string_list (&environ, ENVIRON_STRING_LIST_ID);
+
+ i = 0;
+ while (environ[i])
+ i++;
+
+ /* Make HOME directory the one Emacs starts up in if not specified
+ by resource. */
+ if (getenv ("HOME") == NULL)
+ {
+ environ = (char **) realloc (environ, sizeof (char *) * (i + 2));
+ if (environ)
+ {
+ environ[i] = (char *) malloc (strlen (my_passwd_dir) + 6);
+ if (environ[i])
+ {
+ strcpy (environ[i], "HOME=");
+ strcat (environ[i], my_passwd_dir);
+ }
+ environ[i+1] = 0;
+ i++;
+ }
+ }
+
+ /* Make HOME directory the one Emacs starts up in if not specified
+ by resource. */
+ if (getenv ("MAIL") == NULL)
+ {
+ environ = (char **) realloc (environ, sizeof (char *) * (i + 2));
+ if (environ)
+ {
+ char * path_to_system_folder = get_path_to_system_folder ();
+ environ[i] = (char *) malloc (strlen (path_to_system_folder) + 22);
+ if (environ[i])
+ {
+ strcpy (environ[i], "MAIL=");
+ strcat (environ[i], path_to_system_folder);
+ strcat (environ[i], "Eudora Folder/In");
+ }
+ environ[i+1] = 0;
+ }
+ }
+}
+
+
+/* Return the value of the environment variable NAME. */
+
+char *
+getenv (const char *name)
+{
+ int length = strlen(name);
+ char **e;
+
+ for (e = environ; *e != 0; e++)
+ if (strncmp(*e, name, length) == 0 && (*e)[length] == '=')
+ return &(*e)[length + 1];
+
+ if (strcmp (name, "TMPDIR") == 0)
+ return get_temp_dir_name ();
+
+ return 0;
+}
+
+
+#ifdef __MRC__
+/* see Interfaces&Libraries:Interfaces:CIncludes:signal.h */
+char *sys_siglist[] =
+{
+ "Zero is not a signal!!!",
+ "Abort", /* 1 */
+ "Interactive user interrupt", /* 2 */ "?",
+ "Floating point exception", /* 4 */ "?", "?", "?",
+ "Illegal instruction", /* 8 */ "?", "?", "?", "?", "?", "?", "?",
+ "Segment violation", /* 16 */ "?", "?", "?", "?", "?", "?", "?",
+ "?", "?", "?", "?", "?", "?", "?", "?",
+ "Terminal" /* 32 */
+};
+#elif __MWERKS__
+char *sys_siglist[] =
+{
+ "Zero is not a signal!!!",
+ "Abort",
+ "Floating point exception",
+ "Illegal instruction",
+ "Interactive user interrupt",
+ "Segment violation",
+ "Terminal"
+};
+#else /* not __MRC__ and not __MWERKS__ */
+You lose!!!
+#endif /* not __MRC__ and not __MWERKS__ */
+
+
+#include <utsname.h>
+
+int
+uname (struct utsname *name)
+{
+ char **system_name;
+ system_name = GetString (-16413); /* IM - Resource Manager Reference */
+ if (system_name)
+ {
+ BlockMove (*system_name, name->nodename, (*system_name)[0]+1);
+ p2cstr (name->nodename);
+ return 0;
+ }
+ else
+ return -1;
+}
+
+
+#include <Processes.h>
+#include <EPPC.h>
+
+/* Event class of HLE sent to subprocess. */
+const OSType kEmacsSubprocessSend = 'ESND';
+
+/* Event class of HLE sent back from subprocess. */
+const OSType kEmacsSubprocessReply = 'ERPY';
+
+
+char *
+mystrchr (char *s, char c)
+{
+ while (*s && *s != c)
+ {
+ if (*s == '\\')
+ s++;
+ s++;
+ }
+
+ if (*s)
+ {
+ *s = '\0';
+ return s;
+ }
+ else
+ return NULL;
+}
+
+
+char *
+mystrtok (char *s)
+{
+ while (*s)
+ s++;
+
+ return s + 1;
+}
+
+
+void
+mystrcpy (char *to, char *from)
+{
+ while (*from)
+ {
+ if (*from == '\\')
+ from++;
+ *to++ = *from++;
+ }
+ *to = '\0';
+}
+
+
+/* Start a Mac subprocess. Arguments for it is passed in argv (null
+ terminated). The process should run with the default directory
+ "workdir", read input from "infn", and write output and error to
+ "outfn" and "errfn", resp. The Process Manager call
+ LaunchApplication is used to start the subprocess. We use high
+ level events as the mechanism to pass arguments to the subprocess
+ and to make Emacs wait for the subprocess to terminate and pass
+ back a result code. The bulk of the code here packs the arguments
+ into one message to be passed together with the high level event.
+ Emacs also sometimes starts a subprocess using a shell to perform
+ 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. */
+
+int
+run_mac_command (argv, workdir, infn, outfn, errfn)
+ unsigned char **argv;
+ const char *workdir;
+ const char *infn, *outfn, *errfn;
+{
+#ifdef TARGET_API_MAC_CARBON
+ return -1;
+#else /* not TARGET_API_MAC_CARBON */
+ char macappname[MAXPATHLEN+1], macworkdir[MAXPATHLEN+1];
+ char macinfn[MAXPATHLEN+1], macoutfn[MAXPATHLEN+1], macerrfn[MAXPATHLEN+1];
+ int paramlen, argc, newargc, j, retries;
+ char **newargv, *param, *p;
+ OSErr iErr;
+ FSSpec spec;
+ LaunchParamBlockRec lpbr;
+ EventRecord send_event, reply_event;
+ RgnHandle cursor_region_handle;
+ TargetID targ;
+ unsigned long ref_con, len;
+
+ if (posix_to_mac_pathname (workdir, macworkdir, MAXPATHLEN+1) == 0)
+ return -1;
+ if (posix_to_mac_pathname (infn, macinfn, MAXPATHLEN+1) == 0)
+ return -1;
+ if (posix_to_mac_pathname (outfn, macoutfn, MAXPATHLEN+1) == 0)
+ return -1;
+ if (posix_to_mac_pathname (errfn, macerrfn, MAXPATHLEN+1) == 0)
+ return -1;
+
+ paramlen = strlen (macworkdir) + strlen (macinfn) + strlen (macoutfn)
+ + strlen (macerrfn) + 4; /* count nulls at end of strings */
+
+ argc = 0;
+ while (argv[argc])
+ argc++;
+
+ if (argc == 0)
+ return -1;
+
+ /* If a subprocess is invoked with a shell, we receive 3 arguments
+ of the form: "<path to emacs bins>/sh" "-c" "<path to emacs
+ bins>/<command> <command args>" */
+ j = strlen (argv[0]);
+ if (j >= 3 && strcmp (argv[0]+j-3, "/sh") == 0
+ && argc == 3 && strcmp (argv[1], "-c") == 0)
+ {
+ char *command, *t, tempmacpathname[MAXPATHLEN+1];
+
+ /* The arguments for the command in argv[2] are separated by
+ spaces. Count them and put the count in newargc. */
+ command = (char *) alloca (strlen (argv[2])+2);
+ strcpy (command, argv[2]);
+ if (command[strlen (command) - 1] != ' ')
+ strcat (command, " ");
+
+ t = command;
+ newargc = 0;
+ t = mystrchr (t, ' ');
+ while (t)
+ {
+ newargc++;
+ t = mystrchr (t+1, ' ');
+ }
+
+ newargv = (char **) alloca (sizeof (char *) * newargc);
+
+ t = command;
+ for (j = 0; j < newargc; j++)
+ {
+ newargv[j] = (char *) alloca (strlen (t) + 1);
+ mystrcpy (newargv[j], t);
+
+ t = mystrtok (t);
+ paramlen += strlen (newargv[j]) + 1;
+ }
+
+ if (strncmp (newargv[0], "~emacs/", 7) == 0)
+ {
+ if (posix_to_mac_pathname (newargv[0], tempmacpathname, MAXPATHLEN+1)
+ == 0)
+ return -1;
+ }
+ else
+ { /* sometimes Emacs call "sh" without a path for the command */
+#if 0
+ char *t = (char *) alloca (strlen (newargv[0]) + 7 + 1);
+ strcpy (t, "~emacs/");
+ strcat (t, newargv[0]);
+#endif /* 0 */
+ Lisp_Object path;
+ openp (Vexec_path, build_string (newargv[0]), EXEC_SUFFIXES, &path,
+ 1);
+
+ if (NILP (path))
+ return -1;
+ if (posix_to_mac_pathname (XSTRING (path)->data, tempmacpathname,
+ MAXPATHLEN+1) == 0)
+ return -1;
+ }
+ strcpy (macappname, tempmacpathname);
+ }
+ else
+ {
+ if (posix_to_mac_pathname (argv[0], macappname, MAXPATHLEN+1) == 0)
+ return -1;
+
+ newargv = (char **) alloca (sizeof (char *) * argc);
+ newargc = argc;
+ for (j = 1; j < argc; j++)
+ {
+ if (strncmp (argv[j], "~emacs/", 7) == 0)
+ {
+ char *t = strchr (argv[j], ' ');
+ if (t)
+ {
+ char tempcmdname[MAXPATHLEN+1], tempmaccmdname[MAXPATHLEN+1];
+ strncpy (tempcmdname, argv[j], t-argv[j]);
+ tempcmdname[t-argv[j]] = '\0';
+ if (posix_to_mac_pathname (tempcmdname, tempmaccmdname,
+ MAXPATHLEN+1) == 0)
+ return -1;
+ newargv[j] = (char *) alloca (strlen (tempmaccmdname)
+ + strlen (t) + 1);
+ strcpy (newargv[j], tempmaccmdname);
+ strcat (newargv[j], t);
+ }
+ else
+ {
+ char tempmaccmdname[MAXPATHLEN+1];
+ if (posix_to_mac_pathname (argv[j], tempmaccmdname,
+ MAXPATHLEN+1) == 0)
+ return -1;
+ newargv[j] = (char *) alloca (strlen (tempmaccmdname)+1);
+ strcpy (newargv[j], tempmaccmdname);
+ }
+ }
+ else
+ newargv[j] = argv[j];
+ paramlen += strlen (newargv[j]) + 1;
+ }
+ }
+
+ /* After expanding all the arguments, we now know the length of the
+ parameter block to be sent to the subprocess as a message
+ attached to the HLE. */
+ param = (char *) malloc (paramlen + 1);
+ if (!param)
+ return -1;
+
+ p = param;
+ *p++ = newargc;
+ /* first byte of message contains number of arguments for command */
+ strcpy (p, macworkdir);
+ p += strlen (macworkdir);
+ *p++ = '\0';
+ /* null terminate strings sent so it's possible to use strcpy over there */
+ strcpy (p, macinfn);
+ p += strlen (macinfn);
+ *p++ = '\0';
+ strcpy (p, macoutfn);
+ p += strlen (macoutfn);
+ *p++ = '\0';
+ strcpy (p, macerrfn);
+ p += strlen (macerrfn);
+ *p++ = '\0';
+ for (j = 1; j < newargc; j++)
+ {
+ strcpy (p, newargv[j]);
+ p += strlen (newargv[j]);
+ *p++ = '\0';
+ }
+
+ c2pstr (macappname);
+
+ iErr = FSMakeFSSpec (0, 0, macappname, &spec);
+
+ if (iErr != noErr)
+ {
+ free (param);
+ return -1;
+ }
+
+ lpbr.launchBlockID = extendedBlock;
+ lpbr.launchEPBLength = extendedBlockLen;
+ lpbr.launchControlFlags = launchContinue + launchNoFileFlags;
+ lpbr.launchAppSpec = &spec;
+ lpbr.launchAppParameters = NULL;
+
+ iErr = LaunchApplication (&lpbr); /* call the subprocess */
+ if (iErr != noErr)
+ {
+ free (param);
+ return -1;
+ }
+
+ send_event.what = kHighLevelEvent;
+ send_event.message = kEmacsSubprocessSend;
+ /* Event ID stored in "where" unused */
+
+ retries = 3;
+ /* OS may think current subprocess has terminated if previous one
+ terminated recently. */
+ do
+ {
+ iErr = PostHighLevelEvent (&send_event, &lpbr.launchProcessSN, 0, param,
+ paramlen + 1, receiverIDisPSN);
+ }
+ while (iErr == sessClosedErr && retries-- > 0);
+
+ if (iErr != noErr)
+ {
+ free (param);
+ return -1;
+ }
+
+ cursor_region_handle = NewRgn ();
+
+ /* Wait for the subprocess to finish, when it will send us a ERPY
+ high level event. */
+ while (1)
+ if (WaitNextEvent (highLevelEventMask, &reply_event, 180,
+ cursor_region_handle)
+ && reply_event.message == kEmacsSubprocessReply)
+ break;
+
+ /* The return code is sent through the refCon */
+ iErr = AcceptHighLevelEvent (&targ, &ref_con, NULL, &len);
+ if (iErr != noErr)
+ {
+ DisposeHandle ((Handle) cursor_region_handle);
+ free (param);
+ return -1;
+ }
+
+ DisposeHandle ((Handle) cursor_region_handle);
+ free (param);
+
+ return ref_con;
+#endif /* not TARGET_API_MAC_CARBON */
+}
+
+
+DIR *
+opendir (const char *dirname)
+{
+ char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
+ char mac_pathname[MAXPATHLEN+1], vol_name[MAXPATHLEN+1];
+ DIR *dirp;
+ CInfoPBRec cipb;
+ HVolumeParam vpb;
+ int len, vol_name_len;
+
+ if (find_true_pathname (dirname, true_pathname, MAXPATHLEN+1) == -1)
+ return 0;
+
+ len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
+ if (len > -1)
+ fully_resolved_name[len] = '\0';
+ else
+ strcpy (fully_resolved_name, true_pathname);
+
+ dirp = (DIR *) malloc (sizeof(DIR));
+ if (!dirp)
+ return 0;
+
+ /* Handle special case when dirname is "/": sets up for readir to
+ get all mount volumes. */
+ if (strcmp (fully_resolved_name, "/") == 0)
+ {
+ dirp->getting_volumes = 1; /* special all mounted volumes DIR struct */
+ dirp->current_index = 1; /* index for first volume */
+ return dirp;
+ }
+
+ /* Handle typical cases: not accessing all mounted volumes. */
+ if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
+ return 0;
+
+ /* Emacs calls opendir without the trailing '/', Mac needs trailing ':' */
+ len = strlen (mac_pathname);
+ if (mac_pathname[len - 1] != ':' && len < MAXPATHLEN)
+ strcat (mac_pathname, ":");
+
+ /* Extract volume name */
+ vol_name_len = strchr (mac_pathname, ':') - mac_pathname;
+ strncpy (vol_name, mac_pathname, vol_name_len);
+ vol_name[vol_name_len] = '\0';
+ strcat (vol_name, ":");
+
+ c2pstr (mac_pathname);
+ cipb.hFileInfo.ioNamePtr = mac_pathname;
+ /* using full pathname so vRefNum and DirID ignored */
+ cipb.hFileInfo.ioVRefNum = 0;
+ cipb.hFileInfo.ioDirID = 0;
+ cipb.hFileInfo.ioFDirIndex = 0;
+ /* set to 0 to get information about specific dir or file */
+
+ errno = PBGetCatInfo (&cipb, false);
+ if (errno != noErr)
+ {
+ errno = ENOENT;
+ return 0;
+ }
+
+ if (!(cipb.hFileInfo.ioFlAttrib & 0x10)) /* bit 4 = 1 for directories */
+ return 0; /* not a directory */
+
+ dirp->dir_id = cipb.dirInfo.ioDrDirID; /* used later in readdir */
+ dirp->getting_volumes = 0;
+ dirp->current_index = 1; /* index for first file/directory */
+
+ c2pstr (vol_name);
+ vpb.ioNamePtr = vol_name;
+ /* using full pathname so vRefNum and DirID ignored */
+ vpb.ioVRefNum = 0;
+ vpb.ioVolIndex = -1;
+ errno = PBHGetVInfo ((union HParamBlockRec *) &vpb, false);
+ if (errno != noErr)
+ {
+ errno = ENOENT;
+ return 0;
+ }
+
+ dirp->vol_ref_num = vpb.ioVRefNum;
+
+ return dirp;
+}
+
+int
+closedir (DIR *dp)
+{
+ free (dp);
+
+ return 0;
+}
+
+
+struct dirent *
+readdir (DIR *dp)
+{
+ HParamBlockRec hpblock;
+ CInfoPBRec cipb;
+ static struct dirent s_dirent;
+ static Str255 s_name;
+ int done;
+ char *p;
+
+ /* Handle the root directory containing the mounted volumes. Call
+ PBHGetVInfo specifying an index to obtain the info for a volume.
+ PBHGetVInfo returns an error when it receives an index beyond the
+ last volume, at which time we should return a nil dirent struct
+ pointer. */
+ if (dp->getting_volumes)
+ {
+ hpblock.volumeParam.ioNamePtr = s_name;
+ hpblock.volumeParam.ioVRefNum = 0;
+ hpblock.volumeParam.ioVolIndex = dp->current_index;
+
+ errno = PBHGetVInfo (&hpblock, false);
+ if (errno != noErr)
+ {
+ errno = ENOENT;
+ return 0;
+ }
+
+ p2cstr (s_name);
+ strcat (s_name, "/"); /* need "/" for stat to work correctly */
+
+ dp->current_index++;
+
+ s_dirent.d_ino = hpblock.volumeParam.ioVRefNum;
+ s_dirent.d_name = s_name;
+
+ return &s_dirent;
+ }
+ else
+ {
+ cipb.hFileInfo.ioVRefNum = dp->vol_ref_num;
+ cipb.hFileInfo.ioNamePtr = s_name;
+ /* location to receive filename returned */
+
+ /* return only visible files */
+ done = false;
+ while (!done)
+ {
+ cipb.hFileInfo.ioDirID = dp->dir_id;
+ /* directory ID found by opendir */
+ cipb.hFileInfo.ioFDirIndex = dp->current_index;
+
+ errno = PBGetCatInfo (&cipb, false);
+ if (errno != noErr)
+ {
+ errno = ENOENT;
+ return 0;
+ }
+
+ /* insist on an visibile entry */
+ if (cipb.hFileInfo.ioFlAttrib & 0x10) /* directory? */
+ done = !(cipb.dirInfo.ioDrUsrWds.frFlags & fInvisible);
+ else
+ done = !(cipb.hFileInfo.ioFlFndrInfo.fdFlags & fInvisible);
+
+ dp->current_index++;
+ }
+
+ p2cstr (s_name);
+
+ p = s_name;
+ while (*p)
+ {
+ if (*p == '/')
+ *p = ':';
+ p++;
+ }
+
+ s_dirent.d_ino = cipb.dirInfo.ioDrDirID;
+ /* 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);
+}
+
+
+/* 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. */
+
+static long
+do_applescript (char *script, char **result)
+{
+ AEDesc script_desc, result_desc, error_desc;
+ OSErr error;
+ OSAError osaerror;
+ long length;
+
+ *result = 0;
+
+ error = AECreateDesc (typeChar, script, strlen(script), &script_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 TARGET_API_MAC_CARBON
+ length = AEGetDescDataSize (&result_desc);
+ *result = (char *) xmalloc (length + 1);
+ if (*result)
+ {
+ AEGetDescData (&result_desc, *result, length);
+ *(*result + length) = '\0';
+ }
+#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);
+#endif /* not TARGET_API_MAC_CARBON */
+ }
+
+ AEDisposeDesc (&script_desc);
+ AEDisposeDesc (&result_desc);
+
+ return osaerror;
+}
+
+
+DEFUN ("do-applescript", Fdo_applescript, Sdo_applescript, 1, 1, 0,
+ doc: /* Compile and execute AppleScript SCRIPT and retrieve 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. */)
+ (script)
+ Lisp_Object script;
+{
+ char *result, *temp;
+ Lisp_Object lisp_result;
+ long status;
+
+ CHECK_STRING (script);
+
+ status = do_applescript (XSTRING (script)->data, &result);
+ if (status)
+ {
+ if (!result)
+ error ("AppleScript error %ld", 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);
+ }
+ }
+ else
+ {
+ lisp_result = build_string (result);
+ xfree (result);
+ return lisp_result;
+ }
+}
+
+
+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;
+{
+ char posix_filename[MAXPATHLEN+1];
+
+ CHECK_STRING (mac_filename);
+
+ if (mac_to_posix_pathname (XSTRING (mac_filename)->data, posix_filename,
+ MAXPATHLEN))
+ return build_string (posix_filename);
+ else
+ return Qnil;
+}
+
+
+DEFUN ("posix-file-name-to-mac", Fposix_file_name_to_mac,
+ Sposix_file_name_to_mac, 1, 1, 0,
+ doc: /* Convert Posix filename to Mac form. */)
+ (posix_filename)
+ Lisp_Object posix_filename;
+{
+ char mac_filename[MAXPATHLEN+1];
+
+ CHECK_STRING (posix_filename);
+
+ if (posix_to_mac_pathname (XSTRING (posix_filename)->data, mac_filename,
+ MAXPATHLEN))
+ 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. */)
+ ()
+{
+#if TARGET_API_MAC_CARBON
+ ScrapRef scrap;
+ ScrapFlavorFlags sff;
+ Size s;
+ int i;
+ char *data;
+
+ if (GetCurrentScrap (&scrap) != noErr)
+ return Qnil;
+
+ if (GetScrapFlavorFlags (scrap, kScrapFlavorTypeText, &sff) != noErr)
+ return Qnil;
+
+ if (GetScrapFlavorSize (scrap, kScrapFlavorTypeText, &s) != noErr)
+ return Qnil;
+
+ if ((data = (char*) alloca (s)) == NULL)
+ return Qnil;
+
+ if (GetScrapFlavorData (scrap, kScrapFlavorTypeText, &s, data) != 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 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 */
+
+ rc = GetScrap (my_handle, 'TEXT', &scrap_offset);
+ if (rc < 0)
+ return Qnil;
+
+ HLock (my_handle);
+
+ /* Emacs expects clipboard contents have Unix-style eol's */
+ for (i = 0; i < rc; i++)
+ if ((*my_handle)[i] == '\r')
+ (*my_handle)[i] = '\n';
+
+ value = make_string (*my_handle, rc);
+
+ HUnlock (my_handle);
+
+ DisposeHandle (my_handle);
+
+ return value;
+#endif /* not TARGET_API_MAC_CARBON */
+}
+
+
+/* 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;
+{
+ char *buf;
+ int len, i;
+
+ /* fixme: ignore the push flag for now */
+
+ CHECK_STRING (value);
+
+ len = XSTRING (value)->size;
+ buf = (char *) alloca (len+1);
+ bcopy (XSTRING (value)->data, 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 TARGET_API_MAC_CARBON
+ {
+ ScrapRef scrap;
+ ClearCurrentScrap ();
+ if (GetCurrentScrap (&scrap) != noErr)
+ error ("cannot get current scrap");
+
+ if (PutScrapFlavor (scrap, kScrapFlavorTypeText, kScrapFlavorMaskNone, len,
+ buf) != noErr)
+ error ("cannot put to scrap");
+ }
+#else /* not TARGET_API_MAC_CARBON */
+ ZeroScrap ();
+ PutScrap (len, 'TEXT', buf);
+#endif /* not TARGET_API_MAC_CARBON */
+
+ return Qnil;
+}
+
+
+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;
+{
+ CHECK_SYMBOL (selection);
+
+ /* Return nil for PRIMARY and SECONDARY selections; for CLIPBOARD, check
+ if the clipboard currently has valid text format contents. */
+
+ if (EQ (selection, QCLIPBOARD))
+ {
+ Lisp_Object val = Qnil;
+
+#if TARGET_API_MAC_CARBON
+ ScrapRef scrap;
+ ScrapFlavorFlags sff;
+
+ if (GetCurrentScrap (&scrap) == noErr)
+ if (GetScrapFlavorFlags (scrap, kScrapFlavorTypeText, &sff) == noErr)
+ val = Qt;
+#else /* not TARGET_API_MAC_CARBON */
+ Handle my_handle;
+ long rc, scrap_offset;
+
+ my_handle = NewHandle (0);
+
+ rc = GetScrap (my_handle, 'TEXT', &scrap_offset);
+ if (rc >= 0)
+ val = Qt;
+
+ DisposeHandle (my_handle);
+#endif /* not TARGET_API_MAC_CARBON */
+
+ return val;
+ }
+ return Qnil;
+}
+
+
+void
+syms_of_mac ()
+{
+ QCLIPBOARD = intern ("CLIPBOARD");
+ staticpro (&QCLIPBOARD);
+
+ defsubr (&Smac_paste_function);
+ defsubr (&Smac_cut_function);
+#if 0
+ defsubr (&Sx_selection_exists_p);
+#endif /* 0 */
+
+ defsubr (&Sdo_applescript);
+ defsubr (&Smac_file_name_to_posix);
+ defsubr (&Sposix_file_name_to_mac);
+}