X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/d5db40779d7505244d37476b4f046641f07eea2b..aa5c6b3ea11c0f09415aaa789b1d55f8f4e0e3a1:/src/mac.c diff --git a/src/mac.c b/src/mac.c index f3d65604f5..cce1b858cb 100644 --- a/src/mac.c +++ b/src/mac.c @@ -24,12 +24,17 @@ Boston, MA 02111-1307, USA. */ #include #include +#include #include #include +#include #include #include #include +#include #include +#include +#include #if __MWERKS__ #include #endif @@ -42,6 +47,8 @@ Boston, MA 02111-1307, USA. */ #undef realloc #undef init_process #include +#undef mktime +#define mktime emacs_mktime #undef free #define free unexec_free #undef malloc @@ -68,6 +75,7 @@ Boston, MA 02111-1307, USA. */ #include "process.h" #include "sysselect.h" #include "systime.h" +#include "blockinput.h" Lisp_Object QCLIPBOARD; @@ -89,7 +97,7 @@ string_cat_and_replace (char *s1, const char *s2, int n, char a, char b) int l2 = strlen (s2); char *p = s1 + l1; int i; - + strncat (s1, s2, n); for (i = 0; i < l2; i++) { @@ -102,27 +110,27 @@ string_cat_and_replace (char *s1, const char *s2, int n, char a, char b) /* 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. + full pathname causes a '/' 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++; @@ -157,7 +165,7 @@ mac_to_posix_pathname (const char *mfn, char *ufn, int ufnbuflen) p = pe; } } - + return 1; } @@ -167,20 +175,20 @@ 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) @@ -214,10 +222,10 @@ posix_to_mac_pathname (const char *ufn, char *mfn, int mfnbuflen) 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++; @@ -250,10 +258,26 @@ posix_to_mac_pathname (const char *ufn, char *mfn, int mfnbuflen) p = pe; } } - + return 1; } +#if TARGET_API_MAC_CARBON +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; +} +#endif + #ifndef MAC_OSX /* The following functions with "sys_" prefix are stubs to Unix @@ -309,7 +333,7 @@ stat_noalias (const char *path, struct stat *buf) 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; @@ -319,7 +343,7 @@ stat_noalias (const char *path, struct stat *buf) 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; @@ -375,7 +399,7 @@ lstat (const char *path, struct stat *buf) if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1) return -1; - + return stat_noalias (true_pathname, buf); } @@ -384,16 +408,16 @@ int stat (const char *path, struct stat *sb) { int result; - char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1]; + 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) { @@ -435,10 +459,10 @@ mkdir (const char *dirname, int 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; @@ -446,7 +470,7 @@ mkdir (const char *dirname, int mode) 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; @@ -458,7 +482,7 @@ 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; @@ -466,7 +490,7 @@ sys_rmdir (const char *dirname) 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; } @@ -485,14 +509,14 @@ execvp (const char *path, ...) int utime (const char *path, const struct utimbuf *times) { - char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1]; + 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'; @@ -506,9 +530,9 @@ utime (const char *path, const struct utimbuf *times) cipb.hFileInfo.ioNamePtr = mac_pathname; cipb.hFileInfo.ioVRefNum = 0; cipb.hFileInfo.ioDirID = 0; - cipb.hFileInfo.ioFDirIndex = 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; @@ -547,14 +571,14 @@ utime (const char *path, const struct utimbuf *times) int access (const char *path, int mode) { - char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1]; + 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'; @@ -570,7 +594,7 @@ access (const char *path, int mode) 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; @@ -603,16 +627,16 @@ access (const char *path, int mode) int sys_open (const char *path, int oflag) { - char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1]; + 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'; @@ -640,10 +664,10 @@ sys_open (const char *path, int oflag) int sys_creat (const char *path, mode_t mode) { - char true_pathname[MAXPATHLEN+1]; + char true_pathname[MAXPATHLEN+1]; int len; char mac_pathname[MAXPATHLEN+1]; - + if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1) return -1; @@ -666,13 +690,13 @@ sys_creat (const char *path, mode_t mode) int sys_unlink (const char *path) { - char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1]; + 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'; @@ -721,13 +745,13 @@ 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]; + 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'; @@ -736,7 +760,7 @@ sys_rename (const char * old_name, const char * new_name) 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; @@ -744,7 +768,7 @@ sys_rename (const char * old_name, const char * new_name) mac_old_name, MAXPATHLEN+1)) return -1; - + if (!posix_to_mac_pathname(true_new_pathname, mac_new_name, MAXPATHLEN+1)) return -1; @@ -752,7 +776,7 @@ sys_rename (const char * old_name, const char * new_name) 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); } @@ -762,13 +786,13 @@ 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]; + 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'; @@ -821,6 +845,8 @@ check_alarm () } +extern Boolean mac_wait_next_event (EventRecord *, UInt32, Boolean); + int select (n, rfds, wfds, efds, timeout) int n; @@ -829,49 +855,24 @@ select (n, rfds, wfds, efds, timeout) SELECT_TYPE *efds; struct timeval *timeout; { -#ifdef TARGET_API_MAC_CARBON +#if TARGET_API_MAC_CARBON return 1; #else /* not TARGET_API_MAC_CARBON */ - EMACS_TIME end_time, now; 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; - 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)); + /* 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; return 0; #endif /* not TARGET_API_MAC_CARBON */ @@ -885,18 +886,18 @@ 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; } @@ -905,9 +906,9 @@ 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; } @@ -930,9 +931,9 @@ sys_signal (int signal_num, __signal_func_ptr signal_func) else { #ifdef __MRC__ - __sigfun old_signal_func; + __sigfun old_signal_func; #elif __MWERKS__ - __signal_func_ptr old_signal_func; + __signal_func_ptr old_signal_func; #else You lose!!! #endif @@ -977,7 +978,7 @@ gettimeofday (tp) /* Get time since boot */ Microseconds (&uw_microseconds); - + /* Convert to time since midnight*/ w_microseconds.hi = uw_microseconds.hi; w_microseconds.lo = uw_microseconds.lo; @@ -1017,7 +1018,7 @@ struct tm * sys_gmtime (const time_t *timer) { time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF; - + return gmtime (&unix_time); } @@ -1032,7 +1033,7 @@ sys_localtime (const time_t *timer) #else time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF; #endif - + return localtime (&unix_time); } @@ -1047,7 +1048,7 @@ sys_ctime (const time_t *timer) #else time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF; #endif - + return ctime (&unix_time); } @@ -1065,7 +1066,7 @@ sys_time (time_t *timer) if (timer) *timer = mac_time; - + return mac_time; } @@ -1128,23 +1129,23 @@ 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; + return 0; } @@ -1155,12 +1156,19 @@ mktemp (char *template) static char my_passwd_name[PASSWD_FIELD_SIZE]; static char my_passwd_dir[MAXPATHLEN+1]; -static struct passwd my_passwd = +static struct passwd my_passwd = { my_passwd_name, my_passwd_dir, }; +static struct group my_group = +{ + /* There are no groups on the mac, so we just return "root" as the + group name. */ + "root", +}; + /* Initialized by main () in macterm.c to pathname of emacs directory. */ @@ -1199,7 +1207,7 @@ init_emacs_passwd_dir () } } } - + if (!found) { /* Setting to "/" probably won't work but set it to something @@ -1210,7 +1218,7 @@ init_emacs_passwd_dir () } -static struct passwd emacs_passwd = +static struct passwd emacs_passwd = { "emacs", emacs_passwd_dir, @@ -1246,15 +1254,22 @@ struct passwd * getpwuid (uid_t uid) { if (!my_passwd_inited) - { + { init_my_passwd (); my_passwd_inited = 1; } - + return &my_passwd; } +struct group * +getgrgid (gid_t gid) +{ + return &my_group; +} + + struct passwd * getpwnam (const char *name) { @@ -1262,11 +1277,11 @@ getpwnam (const char *name) return &emacs_passwd; if (!my_passwd_inited) - { + { init_my_passwd (); my_passwd_inited = 1; } - + return &my_passwd; } @@ -1308,7 +1323,7 @@ int sigblock (int mask) { return 0; -} +} void @@ -1390,7 +1405,7 @@ path_from_vol_dir_name (char *path, int man_path_len, short vol_ref_num, err = PBGetCatInfo (&cipb, false); if (err != noErr) return 0; - + p2cstr (dir_name); if (strlen (dir_name) + strlen (path) + 1 >= man_path_len) return 0; @@ -1402,7 +1417,7 @@ path_from_vol_dir_name (char *path, int man_path_len, short vol_ref_num, } while (cipb.dirInfo.ioDrDirID != fsRtDirID); /* stop when we see the volume's root directory */ - + return 1; /* success */ } @@ -1466,7 +1481,7 @@ find_true_pathname (const char *path, char *buf, int bufsiz) return -1; buf[0] = '\0'; - + p = path; if (*p == '/') q = strchr (p + 1, '/'); @@ -1490,10 +1505,10 @@ find_true_pathname (const char *path, char *buf, int bufsiz) p = q + 1; q = strchr(p, '/'); } - + if (len + strlen (p) + 1 >= bufsiz) return -1; - + strcat (buf, p); return len + strlen (p); } @@ -1541,7 +1556,7 @@ int dup2 (int oldd, int newd) { int fd, ret; - + close (newd); fd = dup (oldd); @@ -1652,7 +1667,7 @@ get_temp_dir_name () 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) @@ -1661,18 +1676,18 @@ get_temp_dir_name () &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 + 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); @@ -1691,7 +1706,7 @@ get_temp_dir_name () /* 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 + contains numString strings, a 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 @@ -1745,19 +1760,19 @@ get_path_to_system_folder () 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; } @@ -1772,7 +1787,7 @@ void init_environ () { int i; - + get_string_list (&environ, ENVIRON_STRING_LIST_ID); i = 0; @@ -1916,7 +1931,7 @@ mystrchr (char *s, char c) char * mystrtok (char *s) -{ +{ while (*s) s++; @@ -1958,7 +1973,7 @@ run_mac_command (argv, workdir, infn, outfn, errfn) const char *workdir; const char *infn, *outfn, *errfn; { -#ifdef TARGET_API_MAC_CARBON +#if TARGET_API_MAC_CARBON return -1; #else /* not TARGET_API_MAC_CARBON */ char macappname[MAXPATHLEN+1], macworkdir[MAXPATHLEN+1]; @@ -1972,7 +1987,7 @@ run_mac_command (argv, workdir, infn, outfn, errfn) 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) @@ -1981,7 +1996,7 @@ run_mac_command (argv, workdir, infn, outfn, errfn) 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 */ @@ -2000,14 +2015,14 @@ run_mac_command (argv, workdir, infn, outfn, errfn) && 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, ' '); @@ -2016,9 +2031,9 @@ run_mac_command (argv, workdir, infn, outfn, errfn) newargc++; t = mystrchr (t+1, ' '); } - + newargv = (char **) alloca (sizeof (char *) * newargc); - + t = command; for (j = 0; j < newargc; j++) { @@ -2028,7 +2043,7 @@ run_mac_command (argv, workdir, infn, outfn, errfn) 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) @@ -2043,7 +2058,7 @@ run_mac_command (argv, workdir, infn, outfn, errfn) strcat (t, newargv[0]); #endif /* 0 */ Lisp_Object path; - openp (Vexec_path, build_string (newargv[0]), EXEC_SUFFIXES, &path, + openp (Vexec_path, build_string (newargv[0]), Vexec_suffixes, &path, make_number (X_OK)); if (NILP (path)) @@ -2055,12 +2070,12 @@ run_mac_command (argv, workdir, infn, outfn, errfn) 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; + newargc = argc; for (j = 1; j < argc; j++) { if (strncmp (argv[j], "~emacs/", 7) == 0) @@ -2090,7 +2105,7 @@ run_mac_command (argv, workdir, infn, outfn, errfn) } } else - newargv[j] = argv[j]; + newargv[j] = argv[j]; paramlen += strlen (newargv[j]) + 1; } } @@ -2111,24 +2126,24 @@ run_mac_command (argv, workdir, infn, outfn, errfn) /* null terminate strings sent so it's possible to use strcpy over there */ strcpy (p, macinfn); p += strlen (macinfn); - *p++ = '\0'; + *p++ = '\0'; strcpy (p, macoutfn); p += strlen (macoutfn); - *p++ = '\0'; + *p++ = '\0'; strcpy (p, macerrfn); p += strlen (macerrfn); - *p++ = '\0'; + *p++ = '\0'; for (j = 1; j < newargc; j++) { strcpy (p, newargv[j]); p += strlen (newargv[j]); - *p++ = '\0'; + *p++ = '\0'; } - + c2pstr (macappname); - + iErr = FSMakeFSSpec (0, 0, macappname, &spec); - + if (iErr != noErr) { free (param); @@ -2169,7 +2184,7 @@ run_mac_command (argv, workdir, infn, outfn, errfn) } cursor_region_handle = NewRgn (); - + /* Wait for the subprocess to finish, when it will send us a ERPY high level event. */ while (1) @@ -2177,7 +2192,7 @@ run_mac_command (argv, workdir, infn, outfn, errfn) 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) @@ -2186,7 +2201,7 @@ run_mac_command (argv, workdir, infn, outfn, errfn) free (param); return -1; } - + DisposeHandle ((Handle) cursor_region_handle); free (param); @@ -2198,16 +2213,16 @@ run_mac_command (argv, workdir, infn, outfn, errfn) DIR * opendir (const char *dirname) { - char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1]; + 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'; @@ -2235,7 +2250,7 @@ opendir (const char *dirname) 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); @@ -2249,7 +2264,7 @@ opendir (const char *dirname) 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) { @@ -2277,7 +2292,7 @@ opendir (const char *dirname) } dirp->vol_ref_num = vpb.ioVRefNum; - + return dirp; } @@ -2310,14 +2325,14 @@ readdir (DIR *dp) 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 */ @@ -2325,7 +2340,7 @@ readdir (DIR *dp) s_dirent.d_ino = hpblock.volumeParam.ioVRefNum; s_dirent.d_name = s_name; - + return &s_dirent; } else @@ -2341,25 +2356,25 @@ readdir (DIR *dp) 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 */ + + /* insist on a visible 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) { @@ -2371,7 +2386,7 @@ readdir (DIR *dp) s_dirent.d_ino = cipb.dirInfo.ioDrDirID; /* value unimportant: non-zero for valid file */ s_dirent.d_name = s_name; - + return &s_dirent; } } @@ -2402,7 +2417,7 @@ 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. */ @@ -2528,8 +2543,10 @@ component. */) long status; CHECK_STRING (script); - + + BLOCK_INPUT; status = do_applescript (SDATA (script), &result); + UNBLOCK_INPUT; if (status) { if (!result) @@ -2565,7 +2582,7 @@ DEFUN ("mac-file-name-to-posix", Fmac_file_name_to_posix, char posix_filename[MAXPATHLEN+1]; CHECK_STRING (mac_filename); - + if (mac_to_posix_pathname (SDATA (mac_filename), posix_filename, MAXPATHLEN)) return build_string (posix_filename); @@ -2583,7 +2600,7 @@ DEFUN ("posix-file-name-to-mac", Fposix_file_name_to_mac, char mac_filename[MAXPATHLEN+1]; CHECK_STRING (posix_filename); - + if (posix_to_mac_pathname (SDATA (posix_filename), mac_filename, MAXPATHLEN)) return build_string (mac_filename); @@ -2599,28 +2616,25 @@ DEFUN ("mac-paste-function", Fmac_paste_function, Smac_paste_function, 0, 0, 0, () { #if TARGET_API_MAC_CARBON + OSStatus err; 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) + BLOCK_INPUT; + err = GetCurrentScrap (&scrap); + if (err == noErr) + err = GetScrapFlavorFlags (scrap, kScrapFlavorTypeText, &sff); + if (err == noErr) + err = GetScrapFlavorSize (scrap, kScrapFlavorTypeText, &s); + if (err == noErr && (data = (char*) alloca (s))) + err = GetScrapFlavorData (scrap, kScrapFlavorTypeText, &s, data); + UNBLOCK_INPUT; + if (err != noErr || s == 0) 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') @@ -2648,7 +2662,7 @@ DEFUN ("mac-paste-function", Fmac_paste_function, Smac_paste_function, 0, 0, 0, value = make_string (*my_handle, rc); HUnlock (my_handle); - + DisposeHandle (my_handle); return value; @@ -2669,12 +2683,12 @@ DEFUN ("mac-cut-function", Fmac_cut_function, Smac_cut_function, 1, 2, 0, /* fixme: ignore the push flag for now */ CHECK_STRING (value); - + 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') @@ -2683,19 +2697,28 @@ DEFUN ("mac-cut-function", Fmac_cut_function, Smac_cut_function, 1, 2, 0, #if TARGET_API_MAC_CARBON { ScrapRef scrap; + + BLOCK_INPUT; ClearCurrentScrap (); if (GetCurrentScrap (&scrap) != noErr) - error ("cannot get current scrap"); + { + UNBLOCK_INPUT; + error ("cannot get current scrap"); + } if (PutScrapFlavor (scrap, kScrapFlavorTypeText, kScrapFlavorMaskNone, len, buf) != noErr) - error ("cannot put to scrap"); + { + 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 */ - + return Qnil; } @@ -2724,9 +2747,11 @@ and t is the same as `SECONDARY'. */) ScrapRef scrap; ScrapFlavorFlags sff; + 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; @@ -2745,20 +2770,434 @@ and t is the same as `SECONDARY'. */) return Qnil; } +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. */) + () +{ + check_mac (); + mac_clear_font_name_table (); + return Qnil; +} + +#ifdef MAC_OSX +#undef select + +extern int inhibit_window_system; +extern int noninteractive; + +/* Unlike in X11, window events in Carbon do not come from sockets. + So we cannot simply use `select' to monitor two kinds of inputs: + window events and process outputs. We emulate such functionality + by regarding fd 0 as the window event channel and simultaneously + monitoring both kinds of input channels. It is implemented by + dividing into some cases: + 1. The window event channel is not involved. + -> Use `select'. + 2. Sockets are not involved. + -> Use ReceiveNextEvent. + 3. [If SELECT_USE_CFSOCKET is defined] + Only the window event channel and socket read channels are + 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 + to the event queue that is also used for window events. Then + ReceiveNextEvent can wait for both kinds of inputs. + 4. Otherwise. + -> Periodically poll the window input channel while repeatedly + executing `select' with a short timeout + (SELECT_POLLING_PERIOD_USEC microseconds). */ + +#define SELECT_POLLING_PERIOD_USEC 20000 +#ifdef SELECT_USE_CFSOCKET +#define SELECT_TIMEOUT_THRESHOLD_RUNLOOP 0.2 +#define EVENT_CLASS_SOCK 'Sock' + +static void +socket_callback (s, type, address, data, info) + CFSocketRef s; + CFSocketCallBackType type; + CFDataRef address; + const void *data; + void *info; +{ + EventRef event; + + CreateEvent (NULL, EVENT_CLASS_SOCK, 0, 0, kEventAttributeNone, &event); + PostEventToQueue (GetCurrentEventQueue (), event, kEventPriorityStandard); + ReleaseEvent (event); +} +#endif /* SELECT_USE_CFSOCKET */ + +static int +select_and_poll_event (n, rfds, wfds, efds, timeout) + int n; + SELECT_TYPE *rfds; + SELECT_TYPE *wfds; + SELECT_TYPE *efds; + struct timeval *timeout; +{ + int r; + OSErr err; + + r = select (n, rfds, wfds, efds, timeout); + if (r != -1) + { + BLOCK_INPUT; + err = ReceiveNextEvent (0, NULL, kEventDurationNoWait, + kEventLeaveInQueue, NULL); + UNBLOCK_INPUT; + if (err == noErr) + { + FD_SET (0, rfds); + r++; + } + } + return r; +} + +#if MAC_OS_X_VERSION_MAX_ALLOWED < 1020 +#undef SELECT_INVALIDATE_CFSOCKET +#endif + +int +sys_select (n, rfds, wfds, efds, timeout) + int n; + SELECT_TYPE *rfds; + SELECT_TYPE *wfds; + SELECT_TYPE *efds; + struct timeval *timeout; +{ + OSErr err; + int i, r; + EMACS_TIME select_timeout; + + if (inhibit_window_system || noninteractive + || rfds == NULL || !FD_ISSET (0, rfds)) + return select (n, rfds, wfds, efds, timeout); + + FD_CLR (0, rfds); + + if (wfds == NULL && efds == NULL) + { + int nsocks = 0; + SELECT_TYPE orfds = *rfds; + + EventTimeout timeout_sec = + (timeout + ? (EMACS_SECS (*timeout) * kEventDurationSecond + + EMACS_USECS (*timeout) * kEventDurationMicrosecond) + : kEventDurationForever); + + for (i = 1; i < n; i++) + if (FD_ISSET (i, rfds)) + nsocks++; + + if (nsocks == 0) + { + BLOCK_INPUT; + err = ReceiveNextEvent (0, NULL, timeout_sec, + kEventLeaveInQueue, NULL); + UNBLOCK_INPUT; + if (err == noErr) + { + FD_SET (0, rfds); + return 1; + } + else + return 0; + } + + /* Avoid initial overhead of RunLoop setup for the case that + some input is already available. */ + EMACS_SET_SECS_USECS (select_timeout, 0, 0); + r = select_and_poll_event (n, rfds, wfds, efds, &select_timeout); + if (r != 0 || timeout_sec == 0.0) + return r; + + *rfds = orfds; + +#ifdef SELECT_USE_CFSOCKET + if (timeout_sec > 0 && timeout_sec <= SELECT_TIMEOUT_THRESHOLD_RUNLOOP) + goto poll_periodically; + + { + CFRunLoopRef runloop = + (CFRunLoopRef) GetCFRunLoopFromEventLoop (GetCurrentEventLoop ()); + EventTypeSpec specs[] = {{EVENT_CLASS_SOCK, 0}}; +#ifdef SELECT_INVALIDATE_CFSOCKET + CFSocketRef *shead, *s; +#else + CFRunLoopSourceRef *shead, *s; +#endif + + BLOCK_INPUT; + +#ifdef SELECT_INVALIDATE_CFSOCKET + shead = xmalloc (sizeof (CFSocketRef) * nsocks); +#else + shead = xmalloc (sizeof (CFRunLoopSourceRef) * nsocks); +#endif + s = shead; + for (i = 1; i < n; i++) + if (FD_ISSET (i, rfds)) + { + CFSocketRef socket = + CFSocketCreateWithNative (NULL, i, kCFSocketReadCallBack, + socket_callback, NULL); + CFRunLoopSourceRef source = + CFSocketCreateRunLoopSource (NULL, socket, 0); + +#ifdef SELECT_INVALIDATE_CFSOCKET + CFSocketSetSocketFlags (socket, 0); +#endif + CFRunLoopAddSource (runloop, source, kCFRunLoopDefaultMode); +#ifdef SELECT_INVALIDATE_CFSOCKET + CFRelease (source); + *s = socket; +#else + CFRelease (socket); + *s = source; +#endif + s++; + } + + err = ReceiveNextEvent (0, NULL, timeout_sec, kEventLeaveInQueue, NULL); + + do + { + --s; +#ifdef SELECT_INVALIDATE_CFSOCKET + CFSocketInvalidate (*s); +#else + CFRunLoopRemoveSource (runloop, *s, kCFRunLoopDefaultMode); +#endif + CFRelease (*s); + } + while (s != shead); + + xfree (shead); + + if (err) + { + FD_ZERO (rfds); + r = 0; + } + else + { + FlushEventsMatchingListFromQueue (GetCurrentEventQueue (), + GetEventTypeCount (specs), + specs); + EMACS_SET_SECS_USECS (select_timeout, 0, 0); + r = select_and_poll_event (n, rfds, wfds, efds, &select_timeout); + } + + UNBLOCK_INPUT; + + return r; + } +#endif /* SELECT_USE_CFSOCKET */ + } + + poll_periodically: + { + EMACS_TIME end_time, now, remaining_time; + SELECT_TYPE orfds = *rfds, owfds, oefds; + + if (wfds) + owfds = *wfds; + if (efds) + oefds = *efds; + if (timeout) + { + remaining_time = *timeout; + EMACS_GET_TIME (now); + EMACS_ADD_TIME (end_time, now, remaining_time); + } + + do + { + EMACS_SET_SECS_USECS (select_timeout, 0, SELECT_POLLING_PERIOD_USEC); + if (timeout && EMACS_TIME_LT (remaining_time, select_timeout)) + select_timeout = remaining_time; + r = select_and_poll_event (n, rfds, wfds, efds, &select_timeout); + if (r != 0) + return r; + + *rfds = orfds; + if (wfds) + *wfds = owfds; + if (efds) + *efds = oefds; + + if (timeout) + { + EMACS_GET_TIME (now); + EMACS_SUB_TIME (remaining_time, end_time, now); + } + } + while (!timeout || EMACS_TIME_LT (now, end_time)); + + FD_ZERO (rfds); + if (wfds) + FD_ZERO (wfds); + if (efds) + FD_ZERO (efds); + return 0; + } +} + +/* Set up environment variables so that Emacs can correctly find its + support files when packaged as an application bundle. Directories + placed in /usr/local/share/emacs//, /usr/local/bin, + and /usr/local/libexec/emacs// + by `make install' by default can instead be placed in + .../Emacs.app/Contents/Resources/ and + .../Emacs.app/Contents/MacOS/. Each of these environment variables + is changed only if it is not already set. Presumably if the user + sets an environment variable, he will want to use files in his path + instead of ones in the application bundle. */ +void +init_mac_osx_environment () +{ + CFBundleRef bundle; + CFURLRef bundleURL; + CFStringRef cf_app_bundle_pathname; + int app_bundle_pathname_len; + char *app_bundle_pathname; + char *p, *q; + struct stat st; + + /* Fetch the pathname of the application bundle as a C string into + app_bundle_pathname. */ + + bundle = CFBundleGetMainBundle (); + if (!bundle) + return; + + bundleURL = CFBundleCopyBundleURL (bundle); + if (!bundleURL) + return; + + cf_app_bundle_pathname = CFURLCopyFileSystemPath (bundleURL, + kCFURLPOSIXPathStyle); + app_bundle_pathname_len = CFStringGetLength (cf_app_bundle_pathname); + app_bundle_pathname = (char *) alloca (app_bundle_pathname_len + 1); + + if (!CFStringGetCString (cf_app_bundle_pathname, + app_bundle_pathname, + app_bundle_pathname_len + 1, + kCFStringEncodingISOLatin1)) + { + CFRelease (cf_app_bundle_pathname); + return; + } + + CFRelease (cf_app_bundle_pathname); + + /* P should have sufficient room for the pathname of the bundle plus + the subpath in it leading to the respective directories. Q + should have three times that much room because EMACSLOADPATH can + have the value "::". */ + p = (char *) alloca (app_bundle_pathname_len + 50); + q = (char *) alloca (3 * app_bundle_pathname_len + 150); + if (!getenv ("EMACSLOADPATH")) + { + q[0] = '\0'; + + strcpy (p, app_bundle_pathname); + strcat (p, "/Contents/Resources/lisp"); + if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR) + strcat (q, p); + + strcpy (p, app_bundle_pathname); + strcat (p, "/Contents/Resources/leim"); + if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR) + { + if (q[0] != '\0') + strcat (q, ":"); + strcat (q, p); + } + + strcpy (p, app_bundle_pathname); + strcat (p, "/Contents/Resources/site-lisp"); + if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR) + { + if (q[0] != '\0') + strcat (q, ":"); + strcat (q, p); + } + + if (q[0] != '\0') + setenv ("EMACSLOADPATH", q, 1); + } + + if (!getenv ("EMACSPATH")) + { + q[0] = '\0'; + + strcpy (p, app_bundle_pathname); + strcat (p, "/Contents/MacOS/libexec"); + if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR) + strcat (q, p); + + strcpy (p, app_bundle_pathname); + strcat (p, "/Contents/MacOS/bin"); + if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR) + { + if (q[0] != '\0') + strcat (q, ":"); + strcat (q, p); + } + + if (q[0] != '\0') + setenv ("EMACSPATH", q, 1); + } + + if (!getenv ("EMACSDATA")) + { + strcpy (p, app_bundle_pathname); + strcat (p, "/Contents/Resources/etc"); + if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR) + setenv ("EMACSDATA", p, 1); + } + + if (!getenv ("EMACSDOC")) + { + strcpy (p, app_bundle_pathname); + strcat (p, "/Contents/Resources/etc"); + if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR) + setenv ("EMACSDOC", p, 1); + } + + if (!getenv ("INFOPATH")) + { + strcpy (p, app_bundle_pathname); + strcat (p, "/Contents/Resources/info"); + if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR) + setenv ("INFOPATH", p, 1); + } +} +#endif /* MAC_OSX */ 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 (&Smac_clear_font_name_table); defsubr (&Sdo_applescript); defsubr (&Smac_file_name_to_posix); defsubr (&Sposix_file_name_to_mac); } + +/* arch-tag: 29d30c1f-0c6b-4f88-8a6d-0558d7f9dbff + (do not change this comment) */