1 /* Unix emulation routines for GNU Emacs on the Mac OS.
2 Copyright (C) 2000, 2001 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 /* Contributed by Andrew Choi (akochoi@mac.com). */
37 #include <Carbon/Carbon.h>
39 #define mktime emacs_mktime
41 #define free unexec_free
43 #define malloc unexec_malloc
45 #define realloc unexec_realloc
47 #define init_process emacs_init_process
48 #else /* not MAC_OSX */
52 #endif /* not MAC_OSX */
53 #else /* not HAVE_CARBON */
56 #include <TextUtils.h>
58 #include <Resources.h>
63 #include <AppleScript.h>
66 #include <Processes.h>
68 #endif /* not HAVE_CARBON */
72 #include <sys/types.h>
77 #include <sys/param.h>
86 #include "sysselect.h"
88 #include "blockinput.h"
90 Lisp_Object QCLIPBOARD
;
92 /* An instance of the AppleScript component. */
93 static ComponentInstance as_scripting_component
;
94 /* The single script context used for all script executions. */
95 static OSAID as_script_context
;
98 /* When converting from Mac to Unix pathnames, /'s in folder names are
99 converted to :'s. This function, used in copying folder names,
100 performs a strncat and converts all character a to b in the copy of
101 the string s2 appended to the end of s1. */
104 string_cat_and_replace (char *s1
, const char *s2
, int n
, char a
, char b
)
106 int l1
= strlen (s1
);
107 int l2
= strlen (s2
);
112 for (i
= 0; i
< l2
; i
++)
121 /* Convert a Mac pathname to Posix form. A Mac full pathname is one
122 that does not begin with a ':' and contains at least one ':'. A Mac
123 full pathname causes a '/' to be prepended to the Posix pathname.
124 The algorithm for the rest of the pathname is as follows:
125 For each segment between two ':',
126 if it is non-null, copy as is and then add a '/' at the end,
127 otherwise, insert a "../" into the Posix pathname.
128 Returns 1 if successful; 0 if fails. */
131 mac_to_posix_pathname (const char *mfn
, char *ufn
, int ufnbuflen
)
133 const char *p
, *q
, *pe
;
140 p
= strchr (mfn
, ':');
141 if (p
!= 0 && p
!= mfn
) /* full pathname */
148 pe
= mfn
+ strlen (mfn
);
155 { /* two consecutive ':' */
156 if (strlen (ufn
) + 3 >= ufnbuflen
)
162 if (strlen (ufn
) + (q
- p
) + 1 >= ufnbuflen
)
164 string_cat_and_replace (ufn
, p
, q
- p
, '/', ':');
171 if (strlen (ufn
) + (pe
- p
) >= ufnbuflen
)
173 string_cat_and_replace (ufn
, p
, pe
- p
, '/', ':');
174 /* no separator for last one */
183 extern char *get_temp_dir_name ();
186 /* Convert a Posix pathname to Mac form. Approximately reverse of the
187 above in algorithm. */
190 posix_to_mac_pathname (const char *ufn
, char *mfn
, int mfnbuflen
)
192 const char *p
, *q
, *pe
;
193 char expanded_pathname
[MAXPATHLEN
+1];
202 /* Check for and handle volume names. Last comparison: strangely
203 somewhere "/.emacs" is passed. A temporary fix for now. */
204 if (*p
== '/' && strchr (p
+1, '/') == NULL
&& strcmp (p
, "/.emacs") != 0)
206 if (strlen (p
) + 1 > mfnbuflen
)
213 /* expand to emacs dir found by init_emacs_passwd_dir */
214 if (strncmp (p
, "~emacs/", 7) == 0)
216 struct passwd
*pw
= getpwnam ("emacs");
218 if (strlen (pw
->pw_dir
) + strlen (p
) > MAXPATHLEN
)
220 strcpy (expanded_pathname
, pw
->pw_dir
);
221 strcat (expanded_pathname
, p
);
222 p
= expanded_pathname
;
223 /* now p points to the pathname with emacs dir prefix */
225 else if (strncmp (p
, "/tmp/", 5) == 0)
227 char *t
= get_temp_dir_name ();
229 if (strlen (t
) + strlen (p
) > MAXPATHLEN
)
231 strcpy (expanded_pathname
, t
);
232 strcat (expanded_pathname
, p
);
233 p
= expanded_pathname
;
234 /* now p points to the pathname with emacs dir prefix */
236 else if (*p
!= '/') /* relative pathname */
248 if (q
- p
== 2 && *p
== '.' && *(p
+1) == '.')
250 if (strlen (mfn
) + 1 >= mfnbuflen
)
256 if (strlen (mfn
) + (q
- p
) + 1 >= mfnbuflen
)
258 string_cat_and_replace (mfn
, p
, q
- p
, ':', '/');
265 if (strlen (mfn
) + (pe
- p
) >= mfnbuflen
)
267 string_cat_and_replace (mfn
, p
, pe
- p
, ':', '/');
275 #if TARGET_API_MAC_CARBON
277 cfstring_create_with_utf8_cstring (c_str
)
282 str
= CFStringCreateWithCString (NULL
, c_str
, kCFStringEncodingUTF8
);
284 /* Failed to interpret as UTF 8. Fall back on Mac Roman. */
285 str
= CFStringCreateWithCString (NULL
, c_str
, kCFStringEncodingMacRoman
);
293 /* The following functions with "sys_" prefix are stubs to Unix
294 functions that have already been implemented by CW or MPW. The
295 calls to them in Emacs source course are #define'd to call the sys_
296 versions by the header files s-mac.h. In these stubs pathnames are
297 converted between their Unix and Mac forms. */
300 /* Unix epoch is Jan 1, 1970 while Mac epoch is Jan 1, 1904: 66 years
301 + 17 leap days. These are for adjusting time values returned by
302 MacOS Toolbox functions. */
304 #define MAC_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
308 /* CW Pro 5 epoch is Jan 1, 1900 (aaarghhhhh!); remember, 1900 is not
309 a leap year! This is for adjusting time_t values returned by MSL
311 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 70 + 17) * 24 * 60 * 60)
312 #else /* __MSL__ >= 0x6000 */
313 /* CW changes Pro 6 to follow Unix! */
314 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
315 #endif /* __MSL__ >= 0x6000 */
317 /* MPW library functions follow Unix (confused?). */
318 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
319 #else /* not __MRC__ */
321 #endif /* not __MRC__ */
324 /* Define our own stat function for both MrC and CW. The reason for
325 doing this: "stat" is both the name of a struct and function name:
326 can't use the same trick like that for sys_open, sys_close, etc. to
327 redirect Emacs's calls to our own version that converts Unix style
328 filenames to Mac style filename because all sorts of compilation
329 errors will be generated if stat is #define'd to be sys_stat. */
332 stat_noalias (const char *path
, struct stat
*buf
)
334 char mac_pathname
[MAXPATHLEN
+1];
337 if (posix_to_mac_pathname (path
, mac_pathname
, MAXPATHLEN
+1) == 0)
340 c2pstr (mac_pathname
);
341 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
342 cipb
.hFileInfo
.ioVRefNum
= 0;
343 cipb
.hFileInfo
.ioDirID
= 0;
344 cipb
.hFileInfo
.ioFDirIndex
= 0;
345 /* set to 0 to get information about specific dir or file */
347 errno
= PBGetCatInfo (&cipb
, false);
348 if (errno
== -43) /* -43: fnfErr defined in Errors.h */
353 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* bit 4 = 1 for directories */
355 buf
->st_mode
= S_IFDIR
| S_IREAD
| S_IEXEC
;
357 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x1))
358 buf
->st_mode
|= S_IWRITE
; /* bit 1 = 1 for locked files/directories */
359 buf
->st_ino
= cipb
.dirInfo
.ioDrDirID
;
360 buf
->st_dev
= cipb
.dirInfo
.ioVRefNum
;
361 buf
->st_size
= cipb
.dirInfo
.ioDrNmFls
;
362 /* size of dir = number of files and dirs */
365 = cipb
.dirInfo
.ioDrMdDat
- MAC_UNIX_EPOCH_DIFF
;
366 buf
->st_ctime
= cipb
.dirInfo
.ioDrCrDat
- MAC_UNIX_EPOCH_DIFF
;
370 buf
->st_mode
= S_IFREG
| S_IREAD
;
371 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x1))
372 buf
->st_mode
|= S_IWRITE
; /* bit 1 = 1 for locked files/directories */
373 if (cipb
.hFileInfo
.ioFlFndrInfo
.fdType
== 'APPL')
374 buf
->st_mode
|= S_IEXEC
;
375 buf
->st_ino
= cipb
.hFileInfo
.ioDirID
;
376 buf
->st_dev
= cipb
.hFileInfo
.ioVRefNum
;
377 buf
->st_size
= cipb
.hFileInfo
.ioFlLgLen
;
380 = cipb
.hFileInfo
.ioFlMdDat
- MAC_UNIX_EPOCH_DIFF
;
381 buf
->st_ctime
= cipb
.hFileInfo
.ioFlCrDat
- MAC_UNIX_EPOCH_DIFF
;
384 if (cipb
.hFileInfo
.ioFlFndrInfo
.fdFlags
& 0x8000)
386 /* identify alias files as symlinks */
387 buf
->st_mode
&= ~S_IFREG
;
388 buf
->st_mode
|= S_IFLNK
;
392 buf
->st_uid
= getuid ();
393 buf
->st_gid
= getgid ();
401 lstat (const char *path
, struct stat
*buf
)
404 char true_pathname
[MAXPATHLEN
+1];
406 /* Try looking for the file without resolving aliases first. */
407 if ((result
= stat_noalias (path
, buf
)) >= 0)
410 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
413 return stat_noalias (true_pathname
, buf
);
418 stat (const char *path
, struct stat
*sb
)
421 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
424 if ((result
= stat_noalias (path
, sb
)) >= 0 &&
425 ! (sb
->st_mode
& S_IFLNK
))
428 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
431 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
434 fully_resolved_name
[len
] = '\0';
435 /* in fact our readlink terminates strings */
436 return lstat (fully_resolved_name
, sb
);
439 return lstat (true_pathname
, sb
);
444 /* CW defines fstat in stat.mac.c while MPW does not provide this
445 function. Without the information of how to get from a file
446 descriptor in MPW StdCLib to a Mac OS file spec, it should be hard
447 to implement this function. Fortunately, there is only one place
448 where this function is called in our configuration: in fileio.c,
449 where only the st_dev and st_ino fields are used to determine
450 whether two fildes point to different i-nodes to prevent copying
451 a file onto itself equal. What we have here probably needs
455 fstat (int fildes
, struct stat
*buf
)
458 buf
->st_ino
= fildes
;
459 buf
->st_mode
= S_IFREG
; /* added by T.I. for the copy-file */
460 return 0; /* success */
466 mkdir (const char *dirname
, int mode
)
471 char true_pathname
[MAXPATHLEN
+1], mac_pathname
[MAXPATHLEN
+1];
473 if (find_true_pathname (dirname
, true_pathname
, MAXPATHLEN
+1) == -1)
476 if (posix_to_mac_pathname (true_pathname
, mac_pathname
, MAXPATHLEN
+1) == 0)
479 c2pstr (mac_pathname
);
480 hfpb
.ioNamePtr
= mac_pathname
;
481 hfpb
.ioVRefNum
= 0; /* ignored unless name is invalid */
482 hfpb
.ioDirID
= 0; /* parent is the root */
484 errno
= PBDirCreate ((HParmBlkPtr
) &hfpb
, false);
485 /* just return the Mac OSErr code for now */
486 return errno
== noErr
? 0 : -1;
491 sys_rmdir (const char *dirname
)
494 char mac_pathname
[MAXPATHLEN
+1];
496 if (posix_to_mac_pathname (dirname
, mac_pathname
, MAXPATHLEN
+1) == 0)
499 c2pstr (mac_pathname
);
500 hfpb
.ioNamePtr
= mac_pathname
;
501 hfpb
.ioVRefNum
= 0; /* ignored unless name is invalid */
502 hfpb
.ioDirID
= 0; /* parent is the root */
504 errno
= PBHDelete ((HParmBlkPtr
) &hfpb
, false);
505 return errno
== noErr
? 0 : -1;
510 /* No implementation yet. */
512 execvp (const char *path
, ...)
520 utime (const char *path
, const struct utimbuf
*times
)
522 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
524 char mac_pathname
[MAXPATHLEN
+1];
527 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
530 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
532 fully_resolved_name
[len
] = '\0';
534 strcpy (fully_resolved_name
, true_pathname
);
536 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
539 c2pstr (mac_pathname
);
540 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
541 cipb
.hFileInfo
.ioVRefNum
= 0;
542 cipb
.hFileInfo
.ioDirID
= 0;
543 cipb
.hFileInfo
.ioFDirIndex
= 0;
544 /* set to 0 to get information about specific dir or file */
546 errno
= PBGetCatInfo (&cipb
, false);
550 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* bit 4 = 1 for directories */
553 cipb
.dirInfo
.ioDrMdDat
= times
->modtime
+ MAC_UNIX_EPOCH_DIFF
;
555 GetDateTime (&cipb
.dirInfo
.ioDrMdDat
);
560 cipb
.hFileInfo
.ioFlMdDat
= times
->modtime
+ MAC_UNIX_EPOCH_DIFF
;
562 GetDateTime (&cipb
.hFileInfo
.ioFlMdDat
);
565 errno
= PBSetCatInfo (&cipb
, false);
566 return errno
== noErr
? 0 : -1;
580 /* Like stat, but test for access mode in hfpb.ioFlAttrib */
582 access (const char *path
, int mode
)
584 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
586 char mac_pathname
[MAXPATHLEN
+1];
589 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
592 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
594 fully_resolved_name
[len
] = '\0';
596 strcpy (fully_resolved_name
, true_pathname
);
598 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
601 c2pstr (mac_pathname
);
602 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
603 cipb
.hFileInfo
.ioVRefNum
= 0;
604 cipb
.hFileInfo
.ioDirID
= 0;
605 cipb
.hFileInfo
.ioFDirIndex
= 0;
606 /* set to 0 to get information about specific dir or file */
608 errno
= PBGetCatInfo (&cipb
, false);
612 if (mode
== F_OK
) /* got this far, file exists */
616 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* path refers to a directory */
620 if (cipb
.hFileInfo
.ioFlFndrInfo
.fdType
== 'APPL')
627 return (cipb
.hFileInfo
.ioFlAttrib
& 0x1) ? -1 : 0;
628 /* don't allow if lock bit is on */
634 #define DEV_NULL_FD 0x10000
638 sys_open (const char *path
, int oflag
)
640 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
642 char mac_pathname
[MAXPATHLEN
+1];
644 if (strcmp (path
, "/dev/null") == 0)
645 return DEV_NULL_FD
; /* some bogus fd to be ignored in write */
647 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
650 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
652 fully_resolved_name
[len
] = '\0';
654 strcpy (fully_resolved_name
, true_pathname
);
656 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
661 int res
= open (mac_pathname
, oflag
);
662 /* if (oflag == O_WRONLY || oflag == O_RDWR) */
664 fsetfileinfo (mac_pathname
, 'EMAx', 'TEXT');
666 #else /* not __MRC__ */
667 return open (mac_pathname
, oflag
);
668 #endif /* not __MRC__ */
675 sys_creat (const char *path
, mode_t mode
)
677 char true_pathname
[MAXPATHLEN
+1];
679 char mac_pathname
[MAXPATHLEN
+1];
681 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
684 if (!posix_to_mac_pathname (true_pathname
, mac_pathname
, MAXPATHLEN
+1))
689 int result
= creat (mac_pathname
);
690 fsetfileinfo (mac_pathname
, 'EMAx', 'TEXT');
692 #else /* not __MRC__ */
693 return creat (mac_pathname
, mode
);
694 #endif /* not __MRC__ */
701 sys_unlink (const char *path
)
703 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
705 char mac_pathname
[MAXPATHLEN
+1];
707 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
710 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
712 fully_resolved_name
[len
] = '\0';
714 strcpy (fully_resolved_name
, true_pathname
);
716 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
719 return unlink (mac_pathname
);
725 sys_read (int fildes
, char *buf
, int count
)
727 if (fildes
== 0) /* this should not be used for console input */
730 #if __MSL__ >= 0x6000
731 return _read (fildes
, buf
, count
);
733 return read (fildes
, buf
, count
);
740 sys_write (int fildes
, const char *buf
, int count
)
742 if (fildes
== DEV_NULL_FD
)
745 #if __MSL__ >= 0x6000
746 return _write (fildes
, buf
, count
);
748 return write (fildes
, buf
, count
);
755 sys_rename (const char * old_name
, const char * new_name
)
757 char true_old_pathname
[MAXPATHLEN
+1], true_new_pathname
[MAXPATHLEN
+1];
758 char fully_resolved_old_name
[MAXPATHLEN
+1];
760 char mac_old_name
[MAXPATHLEN
+1], mac_new_name
[MAXPATHLEN
+1];
762 if (find_true_pathname (old_name
, true_old_pathname
, MAXPATHLEN
+1) == -1)
765 len
= readlink (true_old_pathname
, fully_resolved_old_name
, MAXPATHLEN
);
767 fully_resolved_old_name
[len
] = '\0';
769 strcpy (fully_resolved_old_name
, true_old_pathname
);
771 if (find_true_pathname (new_name
, true_new_pathname
, MAXPATHLEN
+1) == -1)
774 if (strcmp (fully_resolved_old_name
, true_new_pathname
) == 0)
777 if (!posix_to_mac_pathname (fully_resolved_old_name
,
782 if (!posix_to_mac_pathname(true_new_pathname
, mac_new_name
, MAXPATHLEN
+1))
785 /* If a file with new_name already exists, rename deletes the old
786 file in Unix. CW version fails in these situation. So we add a
787 call to unlink here. */
788 (void) unlink (mac_new_name
);
790 return rename (mac_old_name
, mac_new_name
);
795 extern FILE *fopen (const char *name
, const char *mode
);
797 sys_fopen (const char *name
, const char *mode
)
799 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
801 char mac_pathname
[MAXPATHLEN
+1];
803 if (find_true_pathname (name
, true_pathname
, MAXPATHLEN
+1) == -1)
806 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
808 fully_resolved_name
[len
] = '\0';
810 strcpy (fully_resolved_name
, true_pathname
);
812 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
817 if (mode
[0] == 'w' || mode
[0] == 'a')
818 fsetfileinfo (mac_pathname
, 'EMAx', 'TEXT');
819 #endif /* not __MRC__ */
820 return fopen (mac_pathname
, mode
);
825 long target_ticks
= 0;
828 __sigfun alarm_signal_func
= (__sigfun
) 0;
830 __signal_func_ptr alarm_signal_func
= (__signal_func_ptr
) 0;
831 #else /* not __MRC__ and not __MWERKS__ */
833 #endif /* not __MRC__ and not __MWERKS__ */
836 /* These functions simulate SIG_ALRM. The stub for function signal
837 stores the signal handler function in alarm_signal_func if a
838 SIG_ALRM is encountered. check_alarm is called in XTread_socket,
839 which emacs calls periodically. A pending alarm is represented by
840 a non-zero target_ticks value. check_alarm calls the handler
841 function pointed to by alarm_signal_func if one has been set up and
842 an alarm is pending. */
847 if (target_ticks
&& TickCount () > target_ticks
)
850 if (alarm_signal_func
)
851 (*alarm_signal_func
)(SIGALRM
);
856 extern Boolean
mac_wait_next_event (EventRecord
*, UInt32
, Boolean
);
859 select (n
, rfds
, wfds
, efds
, timeout
)
864 struct timeval
*timeout
;
866 #if TARGET_API_MAC_CARBON
868 EventTimeout timeout_sec
=
870 ? (EMACS_SECS (*timeout
) * kEventDurationSecond
871 + EMACS_USECS (*timeout
) * kEventDurationMicrosecond
)
872 : kEventDurationForever
);
874 if (FD_ISSET (0, rfds
))
877 err
= ReceiveNextEvent (0, NULL
, timeout_sec
, kEventLeaveInQueue
, NULL
);
885 #else /* not TARGET_API_MAC_CARBON */
887 UInt32 sleep_time
= EMACS_SECS (*timeout
) * 60 +
888 ((EMACS_USECS (*timeout
) * 60) / 1000000);
890 /* Can only handle wait for keyboard input. */
891 if (n
> 1 || wfds
|| efds
)
894 /* Also return true if an event other than a keyDown has occurred.
895 This causes kbd_buffer_get_event in keyboard.c to call
896 read_avail_input which in turn calls XTread_socket to poll for
897 these events. Otherwise these never get processed except but a
898 very slow poll timer. */
899 if (FD_ISSET (0, rfds
) && mac_wait_next_event (&e
, sleep_time
, false))
903 #endif /* not TARGET_API_MAC_CARBON */
907 /* Called in sys_select to wait for an alarm signal to arrive. */
915 if (!target_ticks
) /* no alarm pending */
918 if ((tick
= TickCount ()) < target_ticks
)
919 WaitNextEvent (0, &e
, target_ticks
- tick
, NULL
); /* Accept no event;
920 just wait. by T.I. */
923 if (alarm_signal_func
)
924 (*alarm_signal_func
)(SIGALRM
);
933 long remaining
= target_ticks
? (TickCount () - target_ticks
) / 60 : 0;
935 target_ticks
= seconds
? TickCount () + 60 * seconds
: 0;
937 return (remaining
< 0) ? 0 : (unsigned int) remaining
;
943 extern __sigfun
signal (int signal
, __sigfun signal_func
);
945 sys_signal (int signal_num
, __sigfun signal_func
)
947 extern __signal_func_ptr
signal (int signal
, __signal_func_ptr signal_func
);
949 sys_signal (int signal_num
, __signal_func_ptr signal_func
)
950 #else /* not __MRC__ and not __MWERKS__ */
952 #endif /* not __MRC__ and not __MWERKS__ */
954 if (signal_num
!= SIGALRM
)
955 return signal (signal_num
, signal_func
);
959 __sigfun old_signal_func
;
961 __signal_func_ptr old_signal_func
;
965 old_signal_func
= alarm_signal_func
;
966 alarm_signal_func
= signal_func
;
967 return old_signal_func
;
972 /* gettimeofday should return the amount of time (in a timeval
973 structure) since midnight today. The toolbox function Microseconds
974 returns the number of microseconds (in a UnsignedWide value) since
975 the machine was booted. Also making this complicated is WideAdd,
976 WideSubtract, etc. take wide values. */
983 static wide wall_clock_at_epoch
, clicks_at_epoch
;
984 UnsignedWide uw_microseconds
;
986 time_t sys_time (time_t *);
988 /* If this function is called for the first time, record the number
989 of seconds since midnight and the number of microseconds since
990 boot at the time of this first call. */
995 systime
= sys_time (NULL
);
996 /* Store microseconds since midnight in wall_clock_at_epoch. */
997 WideMultiply (systime
, 1000000L, &wall_clock_at_epoch
);
998 Microseconds (&uw_microseconds
);
999 /* Store microseconds since boot in clicks_at_epoch. */
1000 clicks_at_epoch
.hi
= uw_microseconds
.hi
;
1001 clicks_at_epoch
.lo
= uw_microseconds
.lo
;
1004 /* Get time since boot */
1005 Microseconds (&uw_microseconds
);
1007 /* Convert to time since midnight*/
1008 w_microseconds
.hi
= uw_microseconds
.hi
;
1009 w_microseconds
.lo
= uw_microseconds
.lo
;
1010 WideSubtract (&w_microseconds
, &clicks_at_epoch
);
1011 WideAdd (&w_microseconds
, &wall_clock_at_epoch
);
1012 tp
->tv_sec
= WideDivide (&w_microseconds
, 1000000L, &tp
->tv_usec
);
1020 sleep (unsigned int seconds
)
1022 unsigned long time_up
;
1025 time_up
= TickCount () + seconds
* 60;
1026 while (TickCount () < time_up
)
1028 /* Accept no event; just wait. by T.I. */
1029 WaitNextEvent (0, &e
, 30, NULL
);
1034 #endif /* __MRC__ */
1037 /* The time functions adjust time values according to the difference
1038 between the Unix and CW epoches. */
1041 extern struct tm
*gmtime (const time_t *);
1043 sys_gmtime (const time_t *timer
)
1045 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
1047 return gmtime (&unix_time
);
1052 extern struct tm
*localtime (const time_t *);
1054 sys_localtime (const time_t *timer
)
1056 #if __MSL__ >= 0x6000
1057 time_t unix_time
= *timer
;
1059 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
1062 return localtime (&unix_time
);
1067 extern char *ctime (const time_t *);
1069 sys_ctime (const time_t *timer
)
1071 #if __MSL__ >= 0x6000
1072 time_t unix_time
= *timer
;
1074 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
1077 return ctime (&unix_time
);
1082 extern time_t time (time_t *);
1084 sys_time (time_t *timer
)
1086 #if __MSL__ >= 0x6000
1087 time_t mac_time
= time (NULL
);
1089 time_t mac_time
= time (NULL
) - CW_OR_MPW_UNIX_EPOCH_DIFF
;
1099 /* MPW strftime broken for "%p" format */
1104 sys_strftime (char * s
, size_t maxsize
, const char * format
,
1105 const struct tm
* timeptr
)
1107 if (strcmp (format
, "%p") == 0)
1111 if (timeptr
->tm_hour
< 12)
1123 return strftime (s
, maxsize
, format
, timeptr
);
1125 #endif /* __MRC__ */
1128 /* no subprocesses, empty wait */
1138 croak (char *badfunc
)
1140 printf ("%s not yet implemented\r\n", badfunc
);
1146 index (const char * str
, int chr
)
1148 return strchr (str
, chr
);
1153 mktemp (char *template)
1158 len
= strlen (template);
1160 while (k
>= 0 && template[k
] == 'X')
1163 k
++; /* make k index of first 'X' */
1167 /* Zero filled, number of digits equal to the number of X's. */
1168 sprintf (&template[k
], "%0*d", len
-k
, seqnum
++);
1177 /* Emulate getpwuid, getpwnam and others. */
1179 #define PASSWD_FIELD_SIZE 256
1181 static char my_passwd_name
[PASSWD_FIELD_SIZE
];
1182 static char my_passwd_dir
[MAXPATHLEN
+1];
1184 static struct passwd my_passwd
=
1190 static struct group my_group
=
1192 /* There are no groups on the mac, so we just return "root" as the
1198 /* Initialized by main () in macterm.c to pathname of emacs directory. */
1200 char emacs_passwd_dir
[MAXPATHLEN
+1];
1206 init_emacs_passwd_dir ()
1210 if (getwd (emacs_passwd_dir
) && getwd (my_passwd_dir
))
1212 /* Need pathname of first ancestor that begins with "emacs"
1213 since Mac emacs application is somewhere in the emacs-*
1215 int len
= strlen (emacs_passwd_dir
);
1217 /* j points to the "/" following the directory name being
1220 while (i
>= 0 && !found
)
1222 while (i
>= 0 && emacs_passwd_dir
[i
] != '/')
1224 if (emacs_passwd_dir
[i
] == '/' && i
+5 < len
)
1225 found
= (strncmp (&(emacs_passwd_dir
[i
+1]), "emacs", 5) == 0);
1227 emacs_passwd_dir
[j
+1] = '\0';
1238 /* Setting to "/" probably won't work but set it to something
1240 strcpy (emacs_passwd_dir
, "/");
1241 strcpy (my_passwd_dir
, "/");
1246 static struct passwd emacs_passwd
=
1252 static int my_passwd_inited
= 0;
1260 /* Note: my_passwd_dir initialized in int_emacs_passwd_dir to
1261 directory where Emacs was started. */
1263 owner_name
= (char **) GetResource ('STR ',-16096);
1267 BlockMove ((unsigned char *) *owner_name
,
1268 (unsigned char *) my_passwd_name
,
1270 HUnlock (owner_name
);
1271 p2cstr ((unsigned char *) my_passwd_name
);
1274 my_passwd_name
[0] = 0;
1279 getpwuid (uid_t uid
)
1281 if (!my_passwd_inited
)
1284 my_passwd_inited
= 1;
1292 getgrgid (gid_t gid
)
1299 getpwnam (const char *name
)
1301 if (strcmp (name
, "emacs") == 0)
1302 return &emacs_passwd
;
1304 if (!my_passwd_inited
)
1307 my_passwd_inited
= 1;
1314 /* The functions fork, kill, sigsetmask, sigblock, request_sigio,
1315 setpgrp, setpriority, and unrequest_sigio are defined to be empty
1336 error ("Can't spawn subshell");
1355 request_sigio (void)
1361 unrequest_sigio (void)
1376 pipe (int _fildes
[2])
1383 /* Hard and symbolic links. */
1386 symlink (const char *name1
, const char *name2
)
1394 link (const char *name1
, const char *name2
)
1400 #endif /* ! MAC_OSX */
1402 /* Determine the path name of the file specified by VREFNUM, DIRID,
1403 and NAME and place that in the buffer PATH of length
1406 path_from_vol_dir_name (char *path
, int man_path_len
, short vol_ref_num
,
1407 long dir_id
, ConstStr255Param name
)
1413 if (strlen (name
) > man_path_len
)
1416 memcpy (dir_name
, name
, name
[0]+1);
1417 memcpy (path
, name
, name
[0]+1);
1420 cipb
.dirInfo
.ioDrParID
= dir_id
;
1421 cipb
.dirInfo
.ioNamePtr
= dir_name
;
1425 cipb
.dirInfo
.ioVRefNum
= vol_ref_num
;
1426 cipb
.dirInfo
.ioFDirIndex
= -1;
1427 cipb
.dirInfo
.ioDrDirID
= cipb
.dirInfo
.ioDrParID
;
1428 /* go up to parent each time */
1430 err
= PBGetCatInfo (&cipb
, false);
1435 if (strlen (dir_name
) + strlen (path
) + 1 >= man_path_len
)
1438 strcat (dir_name
, ":");
1439 strcat (dir_name
, path
);
1440 /* attach to front since we're going up directory tree */
1441 strcpy (path
, dir_name
);
1443 while (cipb
.dirInfo
.ioDrDirID
!= fsRtDirID
);
1444 /* stop when we see the volume's root directory */
1446 return 1; /* success */
1451 posix_pathname_to_fsspec (ufn
, fs
)
1455 Str255 mac_pathname
;
1457 if (posix_to_mac_pathname (ufn
, mac_pathname
, sizeof (mac_pathname
)) == 0)
1461 c2pstr (mac_pathname
);
1462 return FSMakeFSSpec (0, 0, mac_pathname
, fs
);
1467 fsspec_to_posix_pathname (fs
, ufn
, ufnbuflen
)
1472 char mac_pathname
[MAXPATHLEN
];
1474 if (path_from_vol_dir_name (mac_pathname
, sizeof (mac_pathname
) - 1,
1475 fs
->vRefNum
, fs
->parID
, fs
->name
)
1476 && mac_to_posix_pathname (mac_pathname
, ufn
, ufnbuflen
))
1485 readlink (const char *path
, char *buf
, int bufsiz
)
1487 char mac_sym_link_name
[MAXPATHLEN
+1];
1490 Boolean target_is_folder
, was_aliased
;
1491 Str255 directory_name
, mac_pathname
;
1494 if (posix_to_mac_pathname (path
, mac_sym_link_name
, MAXPATHLEN
+1) == 0)
1497 c2pstr (mac_sym_link_name
);
1498 err
= FSMakeFSSpec (0, 0, mac_sym_link_name
, &fsspec
);
1505 err
= ResolveAliasFile (&fsspec
, true, &target_is_folder
, &was_aliased
);
1506 if (err
!= noErr
|| !was_aliased
)
1512 if (path_from_vol_dir_name (mac_pathname
, 255, fsspec
.vRefNum
, fsspec
.parID
,
1519 if (mac_to_posix_pathname (mac_pathname
, buf
, bufsiz
) == 0)
1525 return strlen (buf
);
1529 /* Convert a path to one with aliases fully expanded. */
1532 find_true_pathname (const char *path
, char *buf
, int bufsiz
)
1534 char *q
, temp
[MAXPATHLEN
+1];
1538 if (bufsiz
<= 0 || path
== 0 || path
[0] == '\0')
1545 q
= strchr (p
+ 1, '/');
1547 q
= strchr (p
, '/');
1548 len
= 0; /* loop may not be entered, e.g., for "/" */
1553 strncat (temp
, p
, q
- p
);
1554 len
= readlink (temp
, buf
, bufsiz
);
1557 if (strlen (temp
) + 1 > bufsiz
)
1567 if (len
+ strlen (p
) + 1 >= bufsiz
)
1571 return len
+ strlen (p
);
1576 umask (mode_t numask
)
1578 static mode_t mask
= 022;
1579 mode_t oldmask
= mask
;
1586 chmod (const char *path
, mode_t mode
)
1588 /* say it always succeed for now */
1597 return fcntl (oldd
, F_DUPFD
, 0);
1599 /* current implementation of fcntl in fcntl.mac.c simply returns old
1601 return fcntl (oldd
, F_DUPFD
);
1608 /* This is from the original sysdep.c. Emulate BSD dup2. First close
1609 newd if it already exists. Then, attempt to dup oldd. If not
1610 successful, call dup2 recursively until we are, then close the
1611 unsuccessful ones. */
1614 dup2 (int oldd
, int newd
)
1625 ret
= dup2 (oldd
, newd
);
1631 /* let it fail for now */
1648 ioctl (int d
, int request
, void *argp
)
1658 if (fildes
>=0 && fildes
<= 2)
1691 #endif /* __MRC__ */
1695 #if __MSL__ < 0x6000
1703 #endif /* __MWERKS__ */
1705 #endif /* ! MAC_OSX */
1708 /* Return the path to the directory in which Emacs can create
1709 temporary files. The MacOS "temporary items" directory cannot be
1710 used because it removes the file written by a process when it
1711 exits. In that sense it's more like "/dev/null" than "/tmp" (but
1712 again not exactly). And of course Emacs needs to read back the
1713 files written by its subprocesses. So here we write the files to a
1714 directory "Emacs" in the Preferences Folder. This directory is
1715 created if it does not exist. */
1718 get_temp_dir_name ()
1720 static char *temp_dir_name
= NULL
;
1724 Str255 dir_name
, full_path
;
1726 char unix_dir_name
[MAXPATHLEN
+1];
1729 /* Cache directory name with pointer temp_dir_name.
1730 Look for it only the first time. */
1733 err
= FindFolder (kOnSystemDisk
, kPreferencesFolderType
, kCreateFolder
,
1734 &vol_ref_num
, &dir_id
);
1738 if (!path_from_vol_dir_name (full_path
, 255, vol_ref_num
, dir_id
, "\p"))
1741 if (strlen (full_path
) + 6 <= MAXPATHLEN
)
1742 strcat (full_path
, "Emacs:");
1746 if (!mac_to_posix_pathname (full_path
, unix_dir_name
, MAXPATHLEN
+1))
1749 dir
= opendir (unix_dir_name
); /* check whether temp directory exists */
1752 else if (mkdir (unix_dir_name
, 0700) != 0) /* create it if not */
1755 temp_dir_name
= (char *) malloc (strlen (unix_dir_name
) + 1);
1756 strcpy (temp_dir_name
, unix_dir_name
);
1759 return temp_dir_name
;
1764 /* Allocate and construct an array of pointers to strings from a list
1765 of strings stored in a 'STR#' resource. The returned pointer array
1766 is stored in the style of argv and environ: if the 'STR#' resource
1767 contains numString strings, a pointer array with numString+1
1768 elements is returned in which the last entry contains a null
1769 pointer. The pointer to the pointer array is passed by pointer in
1770 parameter t. The resource ID of the 'STR#' resource is passed in
1771 parameter StringListID.
1775 get_string_list (char ***t
, short string_list_id
)
1781 h
= GetResource ('STR#', string_list_id
);
1786 num_strings
= * (short *) p
;
1788 *t
= (char **) malloc (sizeof (char *) * (num_strings
+ 1));
1789 for (i
= 0; i
< num_strings
; i
++)
1791 short length
= *p
++;
1792 (*t
)[i
] = (char *) malloc (length
+ 1);
1793 strncpy ((*t
)[i
], p
, length
);
1794 (*t
)[i
][length
] = '\0';
1797 (*t
)[num_strings
] = 0;
1802 /* Return no string in case GetResource fails. Bug fixed by
1803 Ikegami Tsutomu. Caused MPW build to crash without sym -on
1804 option (no sym -on implies -opt local). */
1805 *t
= (char **) malloc (sizeof (char *));
1812 get_path_to_system_folder ()
1817 Str255 dir_name
, full_path
;
1819 static char system_folder_unix_name
[MAXPATHLEN
+1];
1822 err
= FindFolder (kOnSystemDisk
, kSystemFolderType
, kDontCreateFolder
,
1823 &vol_ref_num
, &dir_id
);
1827 if (!path_from_vol_dir_name (full_path
, 255, vol_ref_num
, dir_id
, "\p"))
1830 if (!mac_to_posix_pathname (full_path
, system_folder_unix_name
,
1834 return system_folder_unix_name
;
1840 #define ENVIRON_STRING_LIST_ID 128
1842 /* Get environment variable definitions from STR# resource. */
1849 get_string_list (&environ
, ENVIRON_STRING_LIST_ID
);
1855 /* Make HOME directory the one Emacs starts up in if not specified
1857 if (getenv ("HOME") == NULL
)
1859 environ
= (char **) realloc (environ
, sizeof (char *) * (i
+ 2));
1862 environ
[i
] = (char *) malloc (strlen (my_passwd_dir
) + 6);
1865 strcpy (environ
[i
], "HOME=");
1866 strcat (environ
[i
], my_passwd_dir
);
1873 /* Make HOME directory the one Emacs starts up in if not specified
1875 if (getenv ("MAIL") == NULL
)
1877 environ
= (char **) realloc (environ
, sizeof (char *) * (i
+ 2));
1880 char * path_to_system_folder
= get_path_to_system_folder ();
1881 environ
[i
] = (char *) malloc (strlen (path_to_system_folder
) + 22);
1884 strcpy (environ
[i
], "MAIL=");
1885 strcat (environ
[i
], path_to_system_folder
);
1886 strcat (environ
[i
], "Eudora Folder/In");
1894 /* Return the value of the environment variable NAME. */
1897 getenv (const char *name
)
1899 int length
= strlen(name
);
1902 for (e
= environ
; *e
!= 0; e
++)
1903 if (strncmp(*e
, name
, length
) == 0 && (*e
)[length
] == '=')
1904 return &(*e
)[length
+ 1];
1906 if (strcmp (name
, "TMPDIR") == 0)
1907 return get_temp_dir_name ();
1914 /* see Interfaces&Libraries:Interfaces:CIncludes:signal.h */
1915 char *sys_siglist
[] =
1917 "Zero is not a signal!!!",
1919 "Interactive user interrupt", /* 2 */ "?",
1920 "Floating point exception", /* 4 */ "?", "?", "?",
1921 "Illegal instruction", /* 8 */ "?", "?", "?", "?", "?", "?", "?",
1922 "Segment violation", /* 16 */ "?", "?", "?", "?", "?", "?", "?",
1923 "?", "?", "?", "?", "?", "?", "?", "?",
1927 char *sys_siglist
[] =
1929 "Zero is not a signal!!!",
1931 "Floating point exception",
1932 "Illegal instruction",
1933 "Interactive user interrupt",
1934 "Segment violation",
1937 #else /* not __MRC__ and not __MWERKS__ */
1939 #endif /* not __MRC__ and not __MWERKS__ */
1942 #include <utsname.h>
1945 uname (struct utsname
*name
)
1948 system_name
= GetString (-16413); /* IM - Resource Manager Reference */
1951 BlockMove (*system_name
, name
->nodename
, (*system_name
)[0]+1);
1952 p2cstr (name
->nodename
);
1960 /* Event class of HLE sent to subprocess. */
1961 const OSType kEmacsSubprocessSend
= 'ESND';
1963 /* Event class of HLE sent back from subprocess. */
1964 const OSType kEmacsSubprocessReply
= 'ERPY';
1968 mystrchr (char *s
, char c
)
1970 while (*s
&& *s
!= c
)
1998 mystrcpy (char *to
, char *from
)
2010 /* Start a Mac subprocess. Arguments for it is passed in argv (null
2011 terminated). The process should run with the default directory
2012 "workdir", read input from "infn", and write output and error to
2013 "outfn" and "errfn", resp. The Process Manager call
2014 LaunchApplication is used to start the subprocess. We use high
2015 level events as the mechanism to pass arguments to the subprocess
2016 and to make Emacs wait for the subprocess to terminate and pass
2017 back a result code. The bulk of the code here packs the arguments
2018 into one message to be passed together with the high level event.
2019 Emacs also sometimes starts a subprocess using a shell to perform
2020 wildcard filename expansion. Since we don't really have a shell on
2021 the Mac, this case is detected and the starting of the shell is
2022 by-passed. We really need to add code here to do filename
2023 expansion to support such functionality. */
2026 run_mac_command (argv
, workdir
, infn
, outfn
, errfn
)
2027 unsigned char **argv
;
2028 const char *workdir
;
2029 const char *infn
, *outfn
, *errfn
;
2031 #if TARGET_API_MAC_CARBON
2033 #else /* not TARGET_API_MAC_CARBON */
2034 char macappname
[MAXPATHLEN
+1], macworkdir
[MAXPATHLEN
+1];
2035 char macinfn
[MAXPATHLEN
+1], macoutfn
[MAXPATHLEN
+1], macerrfn
[MAXPATHLEN
+1];
2036 int paramlen
, argc
, newargc
, j
, retries
;
2037 char **newargv
, *param
, *p
;
2040 LaunchParamBlockRec lpbr
;
2041 EventRecord send_event
, reply_event
;
2042 RgnHandle cursor_region_handle
;
2044 unsigned long ref_con
, len
;
2046 if (posix_to_mac_pathname (workdir
, macworkdir
, MAXPATHLEN
+1) == 0)
2048 if (posix_to_mac_pathname (infn
, macinfn
, MAXPATHLEN
+1) == 0)
2050 if (posix_to_mac_pathname (outfn
, macoutfn
, MAXPATHLEN
+1) == 0)
2052 if (posix_to_mac_pathname (errfn
, macerrfn
, MAXPATHLEN
+1) == 0)
2055 paramlen
= strlen (macworkdir
) + strlen (macinfn
) + strlen (macoutfn
)
2056 + strlen (macerrfn
) + 4; /* count nulls at end of strings */
2065 /* If a subprocess is invoked with a shell, we receive 3 arguments
2066 of the form: "<path to emacs bins>/sh" "-c" "<path to emacs
2067 bins>/<command> <command args>" */
2068 j
= strlen (argv
[0]);
2069 if (j
>= 3 && strcmp (argv
[0]+j
-3, "/sh") == 0
2070 && argc
== 3 && strcmp (argv
[1], "-c") == 0)
2072 char *command
, *t
, tempmacpathname
[MAXPATHLEN
+1];
2074 /* The arguments for the command in argv[2] are separated by
2075 spaces. Count them and put the count in newargc. */
2076 command
= (char *) alloca (strlen (argv
[2])+2);
2077 strcpy (command
, argv
[2]);
2078 if (command
[strlen (command
) - 1] != ' ')
2079 strcat (command
, " ");
2083 t
= mystrchr (t
, ' ');
2087 t
= mystrchr (t
+1, ' ');
2090 newargv
= (char **) alloca (sizeof (char *) * newargc
);
2093 for (j
= 0; j
< newargc
; j
++)
2095 newargv
[j
] = (char *) alloca (strlen (t
) + 1);
2096 mystrcpy (newargv
[j
], t
);
2099 paramlen
+= strlen (newargv
[j
]) + 1;
2102 if (strncmp (newargv
[0], "~emacs/", 7) == 0)
2104 if (posix_to_mac_pathname (newargv
[0], tempmacpathname
, MAXPATHLEN
+1)
2109 { /* sometimes Emacs call "sh" without a path for the command */
2111 char *t
= (char *) alloca (strlen (newargv
[0]) + 7 + 1);
2112 strcpy (t
, "~emacs/");
2113 strcat (t
, newargv
[0]);
2116 openp (Vexec_path
, build_string (newargv
[0]), Vexec_suffixes
, &path
,
2117 make_number (X_OK
));
2121 if (posix_to_mac_pathname (SDATA (path
), tempmacpathname
,
2125 strcpy (macappname
, tempmacpathname
);
2129 if (posix_to_mac_pathname (argv
[0], macappname
, MAXPATHLEN
+1) == 0)
2132 newargv
= (char **) alloca (sizeof (char *) * argc
);
2134 for (j
= 1; j
< argc
; j
++)
2136 if (strncmp (argv
[j
], "~emacs/", 7) == 0)
2138 char *t
= strchr (argv
[j
], ' ');
2141 char tempcmdname
[MAXPATHLEN
+1], tempmaccmdname
[MAXPATHLEN
+1];
2142 strncpy (tempcmdname
, argv
[j
], t
-argv
[j
]);
2143 tempcmdname
[t
-argv
[j
]] = '\0';
2144 if (posix_to_mac_pathname (tempcmdname
, tempmaccmdname
,
2147 newargv
[j
] = (char *) alloca (strlen (tempmaccmdname
)
2149 strcpy (newargv
[j
], tempmaccmdname
);
2150 strcat (newargv
[j
], t
);
2154 char tempmaccmdname
[MAXPATHLEN
+1];
2155 if (posix_to_mac_pathname (argv
[j
], tempmaccmdname
,
2158 newargv
[j
] = (char *) alloca (strlen (tempmaccmdname
)+1);
2159 strcpy (newargv
[j
], tempmaccmdname
);
2163 newargv
[j
] = argv
[j
];
2164 paramlen
+= strlen (newargv
[j
]) + 1;
2168 /* After expanding all the arguments, we now know the length of the
2169 parameter block to be sent to the subprocess as a message
2170 attached to the HLE. */
2171 param
= (char *) malloc (paramlen
+ 1);
2177 /* first byte of message contains number of arguments for command */
2178 strcpy (p
, macworkdir
);
2179 p
+= strlen (macworkdir
);
2181 /* null terminate strings sent so it's possible to use strcpy over there */
2182 strcpy (p
, macinfn
);
2183 p
+= strlen (macinfn
);
2185 strcpy (p
, macoutfn
);
2186 p
+= strlen (macoutfn
);
2188 strcpy (p
, macerrfn
);
2189 p
+= strlen (macerrfn
);
2191 for (j
= 1; j
< newargc
; j
++)
2193 strcpy (p
, newargv
[j
]);
2194 p
+= strlen (newargv
[j
]);
2198 c2pstr (macappname
);
2200 iErr
= FSMakeFSSpec (0, 0, macappname
, &spec
);
2208 lpbr
.launchBlockID
= extendedBlock
;
2209 lpbr
.launchEPBLength
= extendedBlockLen
;
2210 lpbr
.launchControlFlags
= launchContinue
+ launchNoFileFlags
;
2211 lpbr
.launchAppSpec
= &spec
;
2212 lpbr
.launchAppParameters
= NULL
;
2214 iErr
= LaunchApplication (&lpbr
); /* call the subprocess */
2221 send_event
.what
= kHighLevelEvent
;
2222 send_event
.message
= kEmacsSubprocessSend
;
2223 /* Event ID stored in "where" unused */
2226 /* OS may think current subprocess has terminated if previous one
2227 terminated recently. */
2230 iErr
= PostHighLevelEvent (&send_event
, &lpbr
.launchProcessSN
, 0, param
,
2231 paramlen
+ 1, receiverIDisPSN
);
2233 while (iErr
== sessClosedErr
&& retries
-- > 0);
2241 cursor_region_handle
= NewRgn ();
2243 /* Wait for the subprocess to finish, when it will send us a ERPY
2244 high level event. */
2246 if (WaitNextEvent (highLevelEventMask
, &reply_event
, 180,
2247 cursor_region_handle
)
2248 && reply_event
.message
== kEmacsSubprocessReply
)
2251 /* The return code is sent through the refCon */
2252 iErr
= AcceptHighLevelEvent (&targ
, &ref_con
, NULL
, &len
);
2255 DisposeHandle ((Handle
) cursor_region_handle
);
2260 DisposeHandle ((Handle
) cursor_region_handle
);
2264 #endif /* not TARGET_API_MAC_CARBON */
2269 opendir (const char *dirname
)
2271 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
2272 char mac_pathname
[MAXPATHLEN
+1], vol_name
[MAXPATHLEN
+1];
2276 int len
, vol_name_len
;
2278 if (find_true_pathname (dirname
, true_pathname
, MAXPATHLEN
+1) == -1)
2281 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
2283 fully_resolved_name
[len
] = '\0';
2285 strcpy (fully_resolved_name
, true_pathname
);
2287 dirp
= (DIR *) malloc (sizeof(DIR));
2291 /* Handle special case when dirname is "/": sets up for readir to
2292 get all mount volumes. */
2293 if (strcmp (fully_resolved_name
, "/") == 0)
2295 dirp
->getting_volumes
= 1; /* special all mounted volumes DIR struct */
2296 dirp
->current_index
= 1; /* index for first volume */
2300 /* Handle typical cases: not accessing all mounted volumes. */
2301 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
2304 /* Emacs calls opendir without the trailing '/', Mac needs trailing ':' */
2305 len
= strlen (mac_pathname
);
2306 if (mac_pathname
[len
- 1] != ':' && len
< MAXPATHLEN
)
2307 strcat (mac_pathname
, ":");
2309 /* Extract volume name */
2310 vol_name_len
= strchr (mac_pathname
, ':') - mac_pathname
;
2311 strncpy (vol_name
, mac_pathname
, vol_name_len
);
2312 vol_name
[vol_name_len
] = '\0';
2313 strcat (vol_name
, ":");
2315 c2pstr (mac_pathname
);
2316 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
2317 /* using full pathname so vRefNum and DirID ignored */
2318 cipb
.hFileInfo
.ioVRefNum
= 0;
2319 cipb
.hFileInfo
.ioDirID
= 0;
2320 cipb
.hFileInfo
.ioFDirIndex
= 0;
2321 /* set to 0 to get information about specific dir or file */
2323 errno
= PBGetCatInfo (&cipb
, false);
2330 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x10)) /* bit 4 = 1 for directories */
2331 return 0; /* not a directory */
2333 dirp
->dir_id
= cipb
.dirInfo
.ioDrDirID
; /* used later in readdir */
2334 dirp
->getting_volumes
= 0;
2335 dirp
->current_index
= 1; /* index for first file/directory */
2338 vpb
.ioNamePtr
= vol_name
;
2339 /* using full pathname so vRefNum and DirID ignored */
2341 vpb
.ioVolIndex
= -1;
2342 errno
= PBHGetVInfo ((union HParamBlockRec
*) &vpb
, false);
2349 dirp
->vol_ref_num
= vpb
.ioVRefNum
;
2366 HParamBlockRec hpblock
;
2368 static struct dirent s_dirent
;
2369 static Str255 s_name
;
2373 /* Handle the root directory containing the mounted volumes. Call
2374 PBHGetVInfo specifying an index to obtain the info for a volume.
2375 PBHGetVInfo returns an error when it receives an index beyond the
2376 last volume, at which time we should return a nil dirent struct
2378 if (dp
->getting_volumes
)
2380 hpblock
.volumeParam
.ioNamePtr
= s_name
;
2381 hpblock
.volumeParam
.ioVRefNum
= 0;
2382 hpblock
.volumeParam
.ioVolIndex
= dp
->current_index
;
2384 errno
= PBHGetVInfo (&hpblock
, false);
2392 strcat (s_name
, "/"); /* need "/" for stat to work correctly */
2394 dp
->current_index
++;
2396 s_dirent
.d_ino
= hpblock
.volumeParam
.ioVRefNum
;
2397 s_dirent
.d_name
= s_name
;
2403 cipb
.hFileInfo
.ioVRefNum
= dp
->vol_ref_num
;
2404 cipb
.hFileInfo
.ioNamePtr
= s_name
;
2405 /* location to receive filename returned */
2407 /* return only visible files */
2411 cipb
.hFileInfo
.ioDirID
= dp
->dir_id
;
2412 /* directory ID found by opendir */
2413 cipb
.hFileInfo
.ioFDirIndex
= dp
->current_index
;
2415 errno
= PBGetCatInfo (&cipb
, false);
2422 /* insist on a visible entry */
2423 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* directory? */
2424 done
= !(cipb
.dirInfo
.ioDrUsrWds
.frFlags
& fInvisible
);
2426 done
= !(cipb
.hFileInfo
.ioFlFndrInfo
.fdFlags
& fInvisible
);
2428 dp
->current_index
++;
2441 s_dirent
.d_ino
= cipb
.dirInfo
.ioDrDirID
;
2442 /* value unimportant: non-zero for valid file */
2443 s_dirent
.d_name
= s_name
;
2453 char mac_pathname
[MAXPATHLEN
+1];
2454 Str255 directory_name
;
2458 if (path_from_vol_dir_name (mac_pathname
, 255, 0, 0, "\p") == 0)
2461 if (mac_to_posix_pathname (mac_pathname
, path
, MAXPATHLEN
+1) == 0)
2467 #endif /* ! MAC_OSX */
2471 initialize_applescript ()
2476 /* if open fails, as_scripting_component is set to NULL. Its
2477 subsequent use in OSA calls will fail with badComponentInstance
2479 as_scripting_component
= OpenDefaultComponent (kOSAComponentType
,
2480 kAppleScriptSubtype
);
2482 null_desc
.descriptorType
= typeNull
;
2483 null_desc
.dataHandle
= 0;
2484 osaerror
= OSAMakeContext (as_scripting_component
, &null_desc
,
2485 kOSANullScript
, &as_script_context
);
2487 as_script_context
= kOSANullScript
;
2488 /* use default context if create fails */
2492 void terminate_applescript()
2494 OSADispose (as_scripting_component
, as_script_context
);
2495 CloseComponent (as_scripting_component
);
2499 /* Compile and execute the AppleScript SCRIPT and return the error
2500 status as function value. A zero is returned if compilation and
2501 execution is successful, in which case RESULT returns a pointer to
2502 a string containing the resulting script value. Otherwise, the Mac
2503 error code is returned and RESULT returns a pointer to an error
2504 string. In both cases the caller should deallocate the storage
2505 used by the string pointed to by RESULT if it is non-NULL. For
2506 documentation on the MacOS scripting architecture, see Inside
2507 Macintosh - Interapplication Communications: Scripting Components. */
2510 do_applescript (char *script
, char **result
)
2512 AEDesc script_desc
, result_desc
, error_desc
;
2519 if (!as_scripting_component
)
2520 initialize_applescript();
2522 error
= AECreateDesc (typeChar
, script
, strlen(script
), &script_desc
);
2526 osaerror
= OSADoScript (as_scripting_component
, &script_desc
, kOSANullScript
,
2527 typeChar
, kOSAModeNull
, &result_desc
);
2529 if (osaerror
== errOSAScriptError
)
2531 /* error executing AppleScript: retrieve error message */
2532 if (!OSAScriptError (as_scripting_component
, kOSAErrorMessage
, typeChar
,
2535 #if TARGET_API_MAC_CARBON
2536 length
= AEGetDescDataSize (&error_desc
);
2537 *result
= (char *) xmalloc (length
+ 1);
2540 AEGetDescData (&error_desc
, *result
, length
);
2541 *(*result
+ length
) = '\0';
2543 #else /* not TARGET_API_MAC_CARBON */
2544 HLock (error_desc
.dataHandle
);
2545 length
= GetHandleSize(error_desc
.dataHandle
);
2546 *result
= (char *) xmalloc (length
+ 1);
2549 memcpy (*result
, *(error_desc
.dataHandle
), length
);
2550 *(*result
+ length
) = '\0';
2552 HUnlock (error_desc
.dataHandle
);
2553 #endif /* not TARGET_API_MAC_CARBON */
2554 AEDisposeDesc (&error_desc
);
2557 else if (osaerror
== noErr
) /* success: retrieve resulting script value */
2559 #if TARGET_API_MAC_CARBON
2560 length
= AEGetDescDataSize (&result_desc
);
2561 *result
= (char *) xmalloc (length
+ 1);
2564 AEGetDescData (&result_desc
, *result
, length
);
2565 *(*result
+ length
) = '\0';
2567 #else /* not TARGET_API_MAC_CARBON */
2568 HLock (result_desc
.dataHandle
);
2569 length
= GetHandleSize(result_desc
.dataHandle
);
2570 *result
= (char *) xmalloc (length
+ 1);
2573 memcpy (*result
, *(result_desc
.dataHandle
), length
);
2574 *(*result
+ length
) = '\0';
2576 HUnlock (result_desc
.dataHandle
);
2577 #endif /* not TARGET_API_MAC_CARBON */
2578 AEDisposeDesc (&result_desc
);
2581 AEDisposeDesc (&script_desc
);
2587 DEFUN ("do-applescript", Fdo_applescript
, Sdo_applescript
, 1, 1, 0,
2588 doc
: /* Compile and execute AppleScript SCRIPT and retrieve and return the result.
2589 If compilation and execution are successful, the resulting script
2590 value is returned as a string. Otherwise the function aborts and
2591 displays the error message returned by the AppleScript scripting
2596 char *result
, *temp
;
2597 Lisp_Object lisp_result
;
2600 CHECK_STRING (script
);
2603 status
= do_applescript (SDATA (script
), &result
);
2608 error ("AppleScript error %d", status
);
2611 /* Unfortunately only OSADoScript in do_applescript knows how
2612 how large the resulting script value or error message is
2613 going to be and therefore as caller memory must be
2614 deallocated here. It is necessary to free the error
2615 message before calling error to avoid a memory leak. */
2616 temp
= (char *) alloca (strlen (result
) + 1);
2617 strcpy (temp
, result
);
2624 lisp_result
= build_string (result
);
2631 DEFUN ("mac-file-name-to-posix", Fmac_file_name_to_posix
,
2632 Smac_file_name_to_posix
, 1, 1, 0,
2633 doc
: /* Convert Macintosh filename to Posix form. */)
2635 Lisp_Object mac_filename
;
2637 char posix_filename
[MAXPATHLEN
+1];
2639 CHECK_STRING (mac_filename
);
2641 if (mac_to_posix_pathname (SDATA (mac_filename
), posix_filename
,
2643 return build_string (posix_filename
);
2649 DEFUN ("posix-file-name-to-mac", Fposix_file_name_to_mac
,
2650 Sposix_file_name_to_mac
, 1, 1, 0,
2651 doc
: /* Convert Posix filename to Mac form. */)
2653 Lisp_Object posix_filename
;
2655 char mac_filename
[MAXPATHLEN
+1];
2657 CHECK_STRING (posix_filename
);
2659 if (posix_to_mac_pathname (SDATA (posix_filename
), mac_filename
,
2661 return build_string (mac_filename
);
2667 /* set interprogram-paste-function to mac-paste-function in mac-win.el
2668 to enable Emacs to obtain the contents of the Mac clipboard. */
2669 DEFUN ("mac-paste-function", Fmac_paste_function
, Smac_paste_function
, 0, 0, 0,
2670 doc
: /* Return the contents of the Mac clipboard as a string. */)
2673 #if TARGET_API_MAC_CARBON
2676 ScrapFlavorFlags sff
;
2682 err
= GetCurrentScrap (&scrap
);
2684 err
= GetScrapFlavorFlags (scrap
, kScrapFlavorTypeText
, &sff
);
2686 err
= GetScrapFlavorSize (scrap
, kScrapFlavorTypeText
, &s
);
2687 if (err
== noErr
&& (data
= (char*) alloca (s
)))
2688 err
= GetScrapFlavorData (scrap
, kScrapFlavorTypeText
, &s
, data
);
2690 if (err
!= noErr
|| s
== 0)
2693 /* Emacs expects clipboard contents have Unix-style eol's */
2694 for (i
= 0; i
< s
; i
++)
2695 if (data
[i
] == '\r')
2698 return make_string (data
, s
);
2699 #else /* not TARGET_API_MAC_CARBON */
2702 long scrap_offset
, rc
, i
;
2704 my_handle
= NewHandle (0); /* allocate 0-length data area */
2706 rc
= GetScrap (my_handle
, 'TEXT', &scrap_offset
);
2712 /* Emacs expects clipboard contents have Unix-style eol's */
2713 for (i
= 0; i
< rc
; i
++)
2714 if ((*my_handle
)[i
] == '\r')
2715 (*my_handle
)[i
] = '\n';
2717 value
= make_string (*my_handle
, rc
);
2719 HUnlock (my_handle
);
2721 DisposeHandle (my_handle
);
2724 #endif /* not TARGET_API_MAC_CARBON */
2728 /* set interprogram-cut-function to mac-cut-function in mac-win.el
2729 to enable Emacs to write the top of the kill-ring to the Mac clipboard. */
2730 DEFUN ("mac-cut-function", Fmac_cut_function
, Smac_cut_function
, 1, 2, 0,
2731 doc
: /* Put the value of the string parameter to the Mac clipboard. */)
2733 Lisp_Object value
, push
;
2738 /* fixme: ignore the push flag for now */
2740 CHECK_STRING (value
);
2742 len
= SCHARS (value
);
2743 buf
= (char *) alloca (len
+1);
2744 bcopy (SDATA (value
), buf
, len
);
2747 /* convert to Mac-style eol's before sending to clipboard */
2748 for (i
= 0; i
< len
; i
++)
2752 #if TARGET_API_MAC_CARBON
2757 ClearCurrentScrap ();
2758 if (GetCurrentScrap (&scrap
) != noErr
)
2761 error ("cannot get current scrap");
2764 if (PutScrapFlavor (scrap
, kScrapFlavorTypeText
, kScrapFlavorMaskNone
, len
,
2768 error ("cannot put to scrap");
2772 #else /* not TARGET_API_MAC_CARBON */
2774 PutScrap (len
, 'TEXT', buf
);
2775 #endif /* not TARGET_API_MAC_CARBON */
2781 DEFUN ("x-selection-exists-p", Fx_selection_exists_p
, Sx_selection_exists_p
,
2783 doc
: /* Whether there is an owner for the given X Selection.
2784 The arg should be the name of the selection in question, typically one of
2785 the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.
2786 \(Those are literal upper-case symbol names, since that's what X expects.)
2787 For convenience, the symbol nil is the same as `PRIMARY',
2788 and t is the same as `SECONDARY'. */)
2790 Lisp_Object selection
;
2792 CHECK_SYMBOL (selection
);
2794 /* Return nil for PRIMARY and SECONDARY selections; for CLIPBOARD, check
2795 if the clipboard currently has valid text format contents. */
2797 if (EQ (selection
, QCLIPBOARD
))
2799 Lisp_Object val
= Qnil
;
2801 #if TARGET_API_MAC_CARBON
2803 ScrapFlavorFlags sff
;
2806 if (GetCurrentScrap (&scrap
) == noErr
)
2807 if (GetScrapFlavorFlags (scrap
, kScrapFlavorTypeText
, &sff
) == noErr
)
2810 #else /* not TARGET_API_MAC_CARBON */
2812 long rc
, scrap_offset
;
2814 my_handle
= NewHandle (0);
2816 rc
= GetScrap (my_handle
, 'TEXT', &scrap_offset
);
2820 DisposeHandle (my_handle
);
2821 #endif /* not TARGET_API_MAC_CARBON */
2829 DEFUN ("mac-clear-font-name-table", Fmac_clear_font_name_table
, Smac_clear_font_name_table
, 0, 0, 0,
2830 doc
: /* Clear the font name table. */)
2834 mac_clear_font_name_table ();
2841 extern int inhibit_window_system
;
2842 extern int noninteractive
;
2844 /* Unlike in X11, window events in Carbon do not come from sockets.
2845 So we cannot simply use `select' to monitor two kinds of inputs:
2846 window events and process outputs. We emulate such functionality
2847 by regarding fd 0 as the window event channel and simultaneously
2848 monitoring both kinds of input channels. It is implemented by
2849 dividing into some cases:
2850 1. The window event channel is not involved.
2852 2. Sockets are not involved.
2853 -> Use ReceiveNextEvent.
2854 3. [If SELECT_USE_CFSOCKET is defined]
2855 Only the window event channel and socket read channels are
2856 involved, and timeout is not too short (greater than
2857 SELECT_TIMEOUT_THRESHHOLD_RUNLOOP seconds).
2858 -> Create CFSocket for each socket and add it into the current
2859 event RunLoop so that an `ready-to-read' event can be posted
2860 to the event queue that is also used for window events. Then
2861 ReceiveNextEvent can wait for both kinds of inputs.
2863 -> Periodically poll the window input channel while repeatedly
2864 executing `select' with a short timeout
2865 (SELECT_POLLING_PERIOD_USEC microseconds). */
2867 #define SELECT_POLLING_PERIOD_USEC 20000
2868 #ifdef SELECT_USE_CFSOCKET
2869 #define SELECT_TIMEOUT_THRESHOLD_RUNLOOP 0.2
2870 #define EVENT_CLASS_SOCK 'Sock'
2873 socket_callback (s
, type
, address
, data
, info
)
2875 CFSocketCallBackType type
;
2882 CreateEvent (NULL
, EVENT_CLASS_SOCK
, 0, 0, kEventAttributeNone
, &event
);
2883 PostEventToQueue (GetCurrentEventQueue (), event
, kEventPriorityStandard
);
2884 ReleaseEvent (event
);
2886 #endif /* SELECT_USE_CFSOCKET */
2889 select_and_poll_event (n
, rfds
, wfds
, efds
, timeout
)
2894 struct timeval
*timeout
;
2899 r
= select (n
, rfds
, wfds
, efds
, timeout
);
2903 err
= ReceiveNextEvent (0, NULL
, kEventDurationNoWait
,
2904 kEventLeaveInQueue
, NULL
);
2915 #if MAC_OS_X_VERSION_MAX_ALLOWED < 1020
2916 #undef SELECT_INVALIDATE_CFSOCKET
2920 sys_select (n
, rfds
, wfds
, efds
, timeout
)
2925 struct timeval
*timeout
;
2929 EMACS_TIME select_timeout
;
2931 if (inhibit_window_system
|| noninteractive
2932 || rfds
== NULL
|| !FD_ISSET (0, rfds
))
2933 return select (n
, rfds
, wfds
, efds
, timeout
);
2937 if (wfds
== NULL
&& efds
== NULL
)
2940 SELECT_TYPE orfds
= *rfds
;
2942 EventTimeout timeout_sec
=
2944 ? (EMACS_SECS (*timeout
) * kEventDurationSecond
2945 + EMACS_USECS (*timeout
) * kEventDurationMicrosecond
)
2946 : kEventDurationForever
);
2948 for (i
= 1; i
< n
; i
++)
2949 if (FD_ISSET (i
, rfds
))
2955 err
= ReceiveNextEvent (0, NULL
, timeout_sec
,
2956 kEventLeaveInQueue
, NULL
);
2967 /* Avoid initial overhead of RunLoop setup for the case that
2968 some input is already available. */
2969 EMACS_SET_SECS_USECS (select_timeout
, 0, 0);
2970 r
= select_and_poll_event (n
, rfds
, wfds
, efds
, &select_timeout
);
2971 if (r
!= 0 || timeout_sec
== 0.0)
2976 #ifdef SELECT_USE_CFSOCKET
2977 if (timeout_sec
> 0 && timeout_sec
<= SELECT_TIMEOUT_THRESHOLD_RUNLOOP
)
2978 goto poll_periodically
;
2981 CFRunLoopRef runloop
=
2982 (CFRunLoopRef
) GetCFRunLoopFromEventLoop (GetCurrentEventLoop ());
2983 EventTypeSpec specs
[] = {{EVENT_CLASS_SOCK
, 0}};
2984 #ifdef SELECT_INVALIDATE_CFSOCKET
2985 CFSocketRef
*shead
, *s
;
2987 CFRunLoopSourceRef
*shead
, *s
;
2992 #ifdef SELECT_INVALIDATE_CFSOCKET
2993 shead
= xmalloc (sizeof (CFSocketRef
) * nsocks
);
2995 shead
= xmalloc (sizeof (CFRunLoopSourceRef
) * nsocks
);
2998 for (i
= 1; i
< n
; i
++)
2999 if (FD_ISSET (i
, rfds
))
3001 CFSocketRef socket
=
3002 CFSocketCreateWithNative (NULL
, i
, kCFSocketReadCallBack
,
3003 socket_callback
, NULL
);
3004 CFRunLoopSourceRef source
=
3005 CFSocketCreateRunLoopSource (NULL
, socket
, 0);
3007 #ifdef SELECT_INVALIDATE_CFSOCKET
3008 CFSocketSetSocketFlags (socket
, 0);
3010 CFRunLoopAddSource (runloop
, source
, kCFRunLoopDefaultMode
);
3011 #ifdef SELECT_INVALIDATE_CFSOCKET
3021 err
= ReceiveNextEvent (0, NULL
, timeout_sec
, kEventLeaveInQueue
, NULL
);
3026 #ifdef SELECT_INVALIDATE_CFSOCKET
3027 CFSocketInvalidate (*s
);
3029 CFRunLoopRemoveSource (runloop
, *s
, kCFRunLoopDefaultMode
);
3044 FlushEventsMatchingListFromQueue (GetCurrentEventQueue (),
3045 GetEventTypeCount (specs
),
3047 EMACS_SET_SECS_USECS (select_timeout
, 0, 0);
3048 r
= select_and_poll_event (n
, rfds
, wfds
, efds
, &select_timeout
);
3055 #endif /* SELECT_USE_CFSOCKET */
3060 EMACS_TIME end_time
, now
, remaining_time
;
3061 SELECT_TYPE orfds
= *rfds
, owfds
, oefds
;
3069 remaining_time
= *timeout
;
3070 EMACS_GET_TIME (now
);
3071 EMACS_ADD_TIME (end_time
, now
, remaining_time
);
3076 EMACS_SET_SECS_USECS (select_timeout
, 0, SELECT_POLLING_PERIOD_USEC
);
3077 if (timeout
&& EMACS_TIME_LT (remaining_time
, select_timeout
))
3078 select_timeout
= remaining_time
;
3079 r
= select_and_poll_event (n
, rfds
, wfds
, efds
, &select_timeout
);
3091 EMACS_GET_TIME (now
);
3092 EMACS_SUB_TIME (remaining_time
, end_time
, now
);
3095 while (!timeout
|| EMACS_TIME_LT (now
, end_time
));
3106 /* Set up environment variables so that Emacs can correctly find its
3107 support files when packaged as an application bundle. Directories
3108 placed in /usr/local/share/emacs/<emacs-version>/, /usr/local/bin,
3109 and /usr/local/libexec/emacs/<emacs-version>/<system-configuration>
3110 by `make install' by default can instead be placed in
3111 .../Emacs.app/Contents/Resources/ and
3112 .../Emacs.app/Contents/MacOS/. Each of these environment variables
3113 is changed only if it is not already set. Presumably if the user
3114 sets an environment variable, he will want to use files in his path
3115 instead of ones in the application bundle. */
3117 init_mac_osx_environment ()
3121 CFStringRef cf_app_bundle_pathname
;
3122 int app_bundle_pathname_len
;
3123 char *app_bundle_pathname
;
3127 /* Fetch the pathname of the application bundle as a C string into
3128 app_bundle_pathname. */
3130 bundle
= CFBundleGetMainBundle ();
3134 bundleURL
= CFBundleCopyBundleURL (bundle
);
3138 cf_app_bundle_pathname
= CFURLCopyFileSystemPath (bundleURL
,
3139 kCFURLPOSIXPathStyle
);
3140 app_bundle_pathname_len
= CFStringGetLength (cf_app_bundle_pathname
);
3141 app_bundle_pathname
= (char *) alloca (app_bundle_pathname_len
+ 1);
3143 if (!CFStringGetCString (cf_app_bundle_pathname
,
3144 app_bundle_pathname
,
3145 app_bundle_pathname_len
+ 1,
3146 kCFStringEncodingISOLatin1
))
3148 CFRelease (cf_app_bundle_pathname
);
3152 CFRelease (cf_app_bundle_pathname
);
3154 /* P should have sufficient room for the pathname of the bundle plus
3155 the subpath in it leading to the respective directories. Q
3156 should have three times that much room because EMACSLOADPATH can
3157 have the value "<path to lisp dir>:<path to leim dir>:<path to
3159 p
= (char *) alloca (app_bundle_pathname_len
+ 50);
3160 q
= (char *) alloca (3 * app_bundle_pathname_len
+ 150);
3161 if (!getenv ("EMACSLOADPATH"))
3165 strcpy (p
, app_bundle_pathname
);
3166 strcat (p
, "/Contents/Resources/lisp");
3167 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
3170 strcpy (p
, app_bundle_pathname
);
3171 strcat (p
, "/Contents/Resources/leim");
3172 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
3179 strcpy (p
, app_bundle_pathname
);
3180 strcat (p
, "/Contents/Resources/site-lisp");
3181 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
3189 setenv ("EMACSLOADPATH", q
, 1);
3192 if (!getenv ("EMACSPATH"))
3196 strcpy (p
, app_bundle_pathname
);
3197 strcat (p
, "/Contents/MacOS/libexec");
3198 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
3201 strcpy (p
, app_bundle_pathname
);
3202 strcat (p
, "/Contents/MacOS/bin");
3203 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
3211 setenv ("EMACSPATH", q
, 1);
3214 if (!getenv ("EMACSDATA"))
3216 strcpy (p
, app_bundle_pathname
);
3217 strcat (p
, "/Contents/Resources/etc");
3218 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
3219 setenv ("EMACSDATA", p
, 1);
3222 if (!getenv ("EMACSDOC"))
3224 strcpy (p
, app_bundle_pathname
);
3225 strcat (p
, "/Contents/Resources/etc");
3226 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
3227 setenv ("EMACSDOC", p
, 1);
3230 if (!getenv ("INFOPATH"))
3232 strcpy (p
, app_bundle_pathname
);
3233 strcat (p
, "/Contents/Resources/info");
3234 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
3235 setenv ("INFOPATH", p
, 1);
3238 #endif /* MAC_OSX */
3243 QCLIPBOARD
= intern ("CLIPBOARD");
3244 staticpro (&QCLIPBOARD
);
3246 defsubr (&Smac_paste_function
);
3247 defsubr (&Smac_cut_function
);
3248 defsubr (&Sx_selection_exists_p
);
3249 defsubr (&Smac_clear_font_name_table
);
3251 defsubr (&Sdo_applescript
);
3252 defsubr (&Smac_file_name_to_posix
);
3253 defsubr (&Sposix_file_name_to_mac
);
3256 /* arch-tag: 29d30c1f-0c6b-4f88-8a6d-0558d7f9dbff
3257 (do not change this comment) */