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). */
30 #include <sys/types.h>
35 #include <sys/param.h>
49 #include <Carbon/Carbon.h>
51 #define mktime emacs_mktime
53 #define free unexec_free
55 #define malloc unexec_malloc
57 #define realloc unexec_realloc
59 #define init_process emacs_init_process
60 #else /* not MAC_OSX */
63 #include <TextUtils.h>
65 #include <Resources.h>
70 #include <AppleScript.h>
72 #endif /* not MAC_OSX */
76 #include "sysselect.h"
78 #include "blockinput.h"
80 Lisp_Object QCLIPBOARD
;
82 /* An instance of the AppleScript component. */
83 static ComponentInstance as_scripting_component
;
84 /* The single script context used for all script executions. */
85 static OSAID as_script_context
;
88 /* When converting from Mac to Unix pathnames, /'s in folder names are
89 converted to :'s. This function, used in copying folder names,
90 performs a strncat and converts all character a to b in the copy of
91 the string s2 appended to the end of s1. */
94 string_cat_and_replace (char *s1
, const char *s2
, int n
, char a
, char b
)
102 for (i
= 0; i
< l2
; i
++)
111 /* Convert a Mac pathname to Posix form. A Mac full pathname is one
112 that does not begin with a ':' and contains at least one ':'. A Mac
113 full pathname causes a '/' to be prepended to the Posix pathname.
114 The algorithm for the rest of the pathname is as follows:
115 For each segment between two ':',
116 if it is non-null, copy as is and then add a '/' at the end,
117 otherwise, insert a "../" into the Posix pathname.
118 Returns 1 if successful; 0 if fails. */
121 mac_to_posix_pathname (const char *mfn
, char *ufn
, int ufnbuflen
)
123 const char *p
, *q
, *pe
;
130 p
= strchr (mfn
, ':');
131 if (p
!= 0 && p
!= mfn
) /* full pathname */
138 pe
= mfn
+ strlen (mfn
);
145 { /* two consecutive ':' */
146 if (strlen (ufn
) + 3 >= ufnbuflen
)
152 if (strlen (ufn
) + (q
- p
) + 1 >= ufnbuflen
)
154 string_cat_and_replace (ufn
, p
, q
- p
, '/', ':');
161 if (strlen (ufn
) + (pe
- p
) >= ufnbuflen
)
163 string_cat_and_replace (ufn
, p
, pe
- p
, '/', ':');
164 /* no separator for last one */
173 extern char *get_temp_dir_name ();
176 /* Convert a Posix pathname to Mac form. Approximately reverse of the
177 above in algorithm. */
180 posix_to_mac_pathname (const char *ufn
, char *mfn
, int mfnbuflen
)
182 const char *p
, *q
, *pe
;
183 char expanded_pathname
[MAXPATHLEN
+1];
192 /* Check for and handle volume names. Last comparison: strangely
193 somewhere "/.emacs" is passed. A temporary fix for now. */
194 if (*p
== '/' && strchr (p
+1, '/') == NULL
&& strcmp (p
, "/.emacs") != 0)
196 if (strlen (p
) + 1 > mfnbuflen
)
203 /* expand to emacs dir found by init_emacs_passwd_dir */
204 if (strncmp (p
, "~emacs/", 7) == 0)
206 struct passwd
*pw
= getpwnam ("emacs");
208 if (strlen (pw
->pw_dir
) + strlen (p
) > MAXPATHLEN
)
210 strcpy (expanded_pathname
, pw
->pw_dir
);
211 strcat (expanded_pathname
, p
);
212 p
= expanded_pathname
;
213 /* now p points to the pathname with emacs dir prefix */
215 else if (strncmp (p
, "/tmp/", 5) == 0)
217 char *t
= get_temp_dir_name ();
219 if (strlen (t
) + strlen (p
) > MAXPATHLEN
)
221 strcpy (expanded_pathname
, t
);
222 strcat (expanded_pathname
, p
);
223 p
= expanded_pathname
;
224 /* now p points to the pathname with emacs dir prefix */
226 else if (*p
!= '/') /* relative pathname */
238 if (q
- p
== 2 && *p
== '.' && *(p
+1) == '.')
240 if (strlen (mfn
) + 1 >= mfnbuflen
)
246 if (strlen (mfn
) + (q
- p
) + 1 >= mfnbuflen
)
248 string_cat_and_replace (mfn
, p
, q
- p
, ':', '/');
255 if (strlen (mfn
) + (pe
- p
) >= mfnbuflen
)
257 string_cat_and_replace (mfn
, p
, pe
- p
, ':', '/');
265 #if TARGET_API_MAC_CARBON
267 cfstring_create_with_utf8_cstring (c_str
)
272 str
= CFStringCreateWithCString (NULL
, c_str
, kCFStringEncodingUTF8
);
274 /* Failed to interpret as UTF 8. Fall back on Mac Roman. */
275 str
= CFStringCreateWithCString (NULL
, c_str
, kCFStringEncodingMacRoman
);
283 /* The following functions with "sys_" prefix are stubs to Unix
284 functions that have already been implemented by CW or MPW. The
285 calls to them in Emacs source course are #define'd to call the sys_
286 versions by the header files s-mac.h. In these stubs pathnames are
287 converted between their Unix and Mac forms. */
290 /* Unix epoch is Jan 1, 1970 while Mac epoch is Jan 1, 1904: 66 years
291 + 17 leap days. These are for adjusting time values returned by
292 MacOS Toolbox functions. */
294 #define MAC_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
298 /* CW Pro 5 epoch is Jan 1, 1900 (aaarghhhhh!); remember, 1900 is not
299 a leap year! This is for adjusting time_t values returned by MSL
301 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 70 + 17) * 24 * 60 * 60)
302 #else /* __MSL__ >= 0x6000 */
303 /* CW changes Pro 6 to follow Unix! */
304 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
305 #endif /* __MSL__ >= 0x6000 */
307 /* MPW library functions follow Unix (confused?). */
308 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
309 #else /* not __MRC__ */
311 #endif /* not __MRC__ */
314 /* Define our own stat function for both MrC and CW. The reason for
315 doing this: "stat" is both the name of a struct and function name:
316 can't use the same trick like that for sys_open, sys_close, etc. to
317 redirect Emacs's calls to our own version that converts Unix style
318 filenames to Mac style filename because all sorts of compilation
319 errors will be generated if stat is #define'd to be sys_stat. */
322 stat_noalias (const char *path
, struct stat
*buf
)
324 char mac_pathname
[MAXPATHLEN
+1];
327 if (posix_to_mac_pathname (path
, mac_pathname
, MAXPATHLEN
+1) == 0)
330 c2pstr (mac_pathname
);
331 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
332 cipb
.hFileInfo
.ioVRefNum
= 0;
333 cipb
.hFileInfo
.ioDirID
= 0;
334 cipb
.hFileInfo
.ioFDirIndex
= 0;
335 /* set to 0 to get information about specific dir or file */
337 errno
= PBGetCatInfo (&cipb
, false);
338 if (errno
== -43) /* -43: fnfErr defined in Errors.h */
343 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* bit 4 = 1 for directories */
345 buf
->st_mode
= S_IFDIR
| S_IREAD
| S_IEXEC
;
347 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x1))
348 buf
->st_mode
|= S_IWRITE
; /* bit 1 = 1 for locked files/directories */
349 buf
->st_ino
= cipb
.dirInfo
.ioDrDirID
;
350 buf
->st_dev
= cipb
.dirInfo
.ioVRefNum
;
351 buf
->st_size
= cipb
.dirInfo
.ioDrNmFls
;
352 /* size of dir = number of files and dirs */
355 = cipb
.dirInfo
.ioDrMdDat
- MAC_UNIX_EPOCH_DIFF
;
356 buf
->st_ctime
= cipb
.dirInfo
.ioDrCrDat
- MAC_UNIX_EPOCH_DIFF
;
360 buf
->st_mode
= S_IFREG
| S_IREAD
;
361 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x1))
362 buf
->st_mode
|= S_IWRITE
; /* bit 1 = 1 for locked files/directories */
363 if (cipb
.hFileInfo
.ioFlFndrInfo
.fdType
== 'APPL')
364 buf
->st_mode
|= S_IEXEC
;
365 buf
->st_ino
= cipb
.hFileInfo
.ioDirID
;
366 buf
->st_dev
= cipb
.hFileInfo
.ioVRefNum
;
367 buf
->st_size
= cipb
.hFileInfo
.ioFlLgLen
;
370 = cipb
.hFileInfo
.ioFlMdDat
- MAC_UNIX_EPOCH_DIFF
;
371 buf
->st_ctime
= cipb
.hFileInfo
.ioFlCrDat
- MAC_UNIX_EPOCH_DIFF
;
374 if (cipb
.hFileInfo
.ioFlFndrInfo
.fdFlags
& 0x8000)
376 /* identify alias files as symlinks */
377 buf
->st_mode
&= ~S_IFREG
;
378 buf
->st_mode
|= S_IFLNK
;
382 buf
->st_uid
= getuid ();
383 buf
->st_gid
= getgid ();
391 lstat (const char *path
, struct stat
*buf
)
394 char true_pathname
[MAXPATHLEN
+1];
396 /* Try looking for the file without resolving aliases first. */
397 if ((result
= stat_noalias (path
, buf
)) >= 0)
400 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
403 return stat_noalias (true_pathname
, buf
);
408 stat (const char *path
, struct stat
*sb
)
411 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
414 if ((result
= stat_noalias (path
, sb
)) >= 0 &&
415 ! (sb
->st_mode
& S_IFLNK
))
418 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
421 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
424 fully_resolved_name
[len
] = '\0';
425 /* in fact our readlink terminates strings */
426 return lstat (fully_resolved_name
, sb
);
429 return lstat (true_pathname
, sb
);
434 /* CW defines fstat in stat.mac.c while MPW does not provide this
435 function. Without the information of how to get from a file
436 descriptor in MPW StdCLib to a Mac OS file spec, it should be hard
437 to implement this function. Fortunately, there is only one place
438 where this function is called in our configuration: in fileio.c,
439 where only the st_dev and st_ino fields are used to determine
440 whether two fildes point to different i-nodes to prevent copying
441 a file onto itself equal. What we have here probably needs
445 fstat (int fildes
, struct stat
*buf
)
448 buf
->st_ino
= fildes
;
449 buf
->st_mode
= S_IFREG
; /* added by T.I. for the copy-file */
450 return 0; /* success */
456 mkdir (const char *dirname
, int mode
)
461 char true_pathname
[MAXPATHLEN
+1], mac_pathname
[MAXPATHLEN
+1];
463 if (find_true_pathname (dirname
, true_pathname
, MAXPATHLEN
+1) == -1)
466 if (posix_to_mac_pathname (true_pathname
, mac_pathname
, MAXPATHLEN
+1) == 0)
469 c2pstr (mac_pathname
);
470 hfpb
.ioNamePtr
= mac_pathname
;
471 hfpb
.ioVRefNum
= 0; /* ignored unless name is invalid */
472 hfpb
.ioDirID
= 0; /* parent is the root */
474 errno
= PBDirCreate ((HParmBlkPtr
) &hfpb
, false);
475 /* just return the Mac OSErr code for now */
476 return errno
== noErr
? 0 : -1;
481 sys_rmdir (const char *dirname
)
484 char mac_pathname
[MAXPATHLEN
+1];
486 if (posix_to_mac_pathname (dirname
, mac_pathname
, MAXPATHLEN
+1) == 0)
489 c2pstr (mac_pathname
);
490 hfpb
.ioNamePtr
= mac_pathname
;
491 hfpb
.ioVRefNum
= 0; /* ignored unless name is invalid */
492 hfpb
.ioDirID
= 0; /* parent is the root */
494 errno
= PBHDelete ((HParmBlkPtr
) &hfpb
, false);
495 return errno
== noErr
? 0 : -1;
500 /* No implementation yet. */
502 execvp (const char *path
, ...)
510 utime (const char *path
, const struct utimbuf
*times
)
512 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
514 char mac_pathname
[MAXPATHLEN
+1];
517 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
520 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
522 fully_resolved_name
[len
] = '\0';
524 strcpy (fully_resolved_name
, true_pathname
);
526 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
529 c2pstr (mac_pathname
);
530 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
531 cipb
.hFileInfo
.ioVRefNum
= 0;
532 cipb
.hFileInfo
.ioDirID
= 0;
533 cipb
.hFileInfo
.ioFDirIndex
= 0;
534 /* set to 0 to get information about specific dir or file */
536 errno
= PBGetCatInfo (&cipb
, false);
540 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* bit 4 = 1 for directories */
543 cipb
.dirInfo
.ioDrMdDat
= times
->modtime
+ MAC_UNIX_EPOCH_DIFF
;
545 GetDateTime (&cipb
.dirInfo
.ioDrMdDat
);
550 cipb
.hFileInfo
.ioFlMdDat
= times
->modtime
+ MAC_UNIX_EPOCH_DIFF
;
552 GetDateTime (&cipb
.hFileInfo
.ioFlMdDat
);
555 errno
= PBSetCatInfo (&cipb
, false);
556 return errno
== noErr
? 0 : -1;
570 /* Like stat, but test for access mode in hfpb.ioFlAttrib */
572 access (const char *path
, int mode
)
574 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
576 char mac_pathname
[MAXPATHLEN
+1];
579 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
582 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
584 fully_resolved_name
[len
] = '\0';
586 strcpy (fully_resolved_name
, true_pathname
);
588 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
591 c2pstr (mac_pathname
);
592 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
593 cipb
.hFileInfo
.ioVRefNum
= 0;
594 cipb
.hFileInfo
.ioDirID
= 0;
595 cipb
.hFileInfo
.ioFDirIndex
= 0;
596 /* set to 0 to get information about specific dir or file */
598 errno
= PBGetCatInfo (&cipb
, false);
602 if (mode
== F_OK
) /* got this far, file exists */
606 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* path refers to a directory */
610 if (cipb
.hFileInfo
.ioFlFndrInfo
.fdType
== 'APPL')
617 return (cipb
.hFileInfo
.ioFlAttrib
& 0x1) ? -1 : 0;
618 /* don't allow if lock bit is on */
624 #define DEV_NULL_FD 0x10000
628 sys_open (const char *path
, int oflag
)
630 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
632 char mac_pathname
[MAXPATHLEN
+1];
634 if (strcmp (path
, "/dev/null") == 0)
635 return DEV_NULL_FD
; /* some bogus fd to be ignored in write */
637 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
640 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
642 fully_resolved_name
[len
] = '\0';
644 strcpy (fully_resolved_name
, true_pathname
);
646 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
651 int res
= open (mac_pathname
, oflag
);
652 /* if (oflag == O_WRONLY || oflag == O_RDWR) */
654 fsetfileinfo (mac_pathname
, 'EMAx', 'TEXT');
656 #else /* not __MRC__ */
657 return open (mac_pathname
, oflag
);
658 #endif /* not __MRC__ */
665 sys_creat (const char *path
, mode_t mode
)
667 char true_pathname
[MAXPATHLEN
+1];
669 char mac_pathname
[MAXPATHLEN
+1];
671 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
674 if (!posix_to_mac_pathname (true_pathname
, mac_pathname
, MAXPATHLEN
+1))
679 int result
= creat (mac_pathname
);
680 fsetfileinfo (mac_pathname
, 'EMAx', 'TEXT');
682 #else /* not __MRC__ */
683 return creat (mac_pathname
, mode
);
684 #endif /* not __MRC__ */
691 sys_unlink (const char *path
)
693 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
695 char mac_pathname
[MAXPATHLEN
+1];
697 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
700 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
702 fully_resolved_name
[len
] = '\0';
704 strcpy (fully_resolved_name
, true_pathname
);
706 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
709 return unlink (mac_pathname
);
715 sys_read (int fildes
, char *buf
, int count
)
717 if (fildes
== 0) /* this should not be used for console input */
720 #if __MSL__ >= 0x6000
721 return _read (fildes
, buf
, count
);
723 return read (fildes
, buf
, count
);
730 sys_write (int fildes
, const char *buf
, int count
)
732 if (fildes
== DEV_NULL_FD
)
735 #if __MSL__ >= 0x6000
736 return _write (fildes
, buf
, count
);
738 return write (fildes
, buf
, count
);
745 sys_rename (const char * old_name
, const char * new_name
)
747 char true_old_pathname
[MAXPATHLEN
+1], true_new_pathname
[MAXPATHLEN
+1];
748 char fully_resolved_old_name
[MAXPATHLEN
+1];
750 char mac_old_name
[MAXPATHLEN
+1], mac_new_name
[MAXPATHLEN
+1];
752 if (find_true_pathname (old_name
, true_old_pathname
, MAXPATHLEN
+1) == -1)
755 len
= readlink (true_old_pathname
, fully_resolved_old_name
, MAXPATHLEN
);
757 fully_resolved_old_name
[len
] = '\0';
759 strcpy (fully_resolved_old_name
, true_old_pathname
);
761 if (find_true_pathname (new_name
, true_new_pathname
, MAXPATHLEN
+1) == -1)
764 if (strcmp (fully_resolved_old_name
, true_new_pathname
) == 0)
767 if (!posix_to_mac_pathname (fully_resolved_old_name
,
772 if (!posix_to_mac_pathname(true_new_pathname
, mac_new_name
, MAXPATHLEN
+1))
775 /* If a file with new_name already exists, rename deletes the old
776 file in Unix. CW version fails in these situation. So we add a
777 call to unlink here. */
778 (void) unlink (mac_new_name
);
780 return rename (mac_old_name
, mac_new_name
);
785 extern FILE *fopen (const char *name
, const char *mode
);
787 sys_fopen (const char *name
, const char *mode
)
789 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
791 char mac_pathname
[MAXPATHLEN
+1];
793 if (find_true_pathname (name
, true_pathname
, MAXPATHLEN
+1) == -1)
796 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
798 fully_resolved_name
[len
] = '\0';
800 strcpy (fully_resolved_name
, true_pathname
);
802 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
807 if (mode
[0] == 'w' || mode
[0] == 'a')
808 fsetfileinfo (mac_pathname
, 'EMAx', 'TEXT');
809 #endif /* not __MRC__ */
810 return fopen (mac_pathname
, mode
);
817 long target_ticks
= 0;
820 __sigfun alarm_signal_func
= (__sigfun
) 0;
822 __signal_func_ptr alarm_signal_func
= (__signal_func_ptr
) 0;
823 #else /* not __MRC__ and not __MWERKS__ */
825 #endif /* not __MRC__ and not __MWERKS__ */
828 /* These functions simulate SIG_ALRM. The stub for function signal
829 stores the signal handler function in alarm_signal_func if a
830 SIG_ALRM is encountered. check_alarm is called in XTread_socket,
831 which emacs calls periodically. A pending alarm is represented by
832 a non-zero target_ticks value. check_alarm calls the handler
833 function pointed to by alarm_signal_func if one has been set up and
834 an alarm is pending. */
839 if (target_ticks
&& TickCount () > target_ticks
)
842 if (alarm_signal_func
)
843 (*alarm_signal_func
)(SIGALRM
);
848 extern Boolean
mac_wait_next_event (EventRecord
*, UInt32
, Boolean
);
851 select (n
, rfds
, wfds
, efds
, timeout
)
856 struct timeval
*timeout
;
858 #if TARGET_API_MAC_CARBON
860 #else /* not TARGET_API_MAC_CARBON */
862 UInt32 sleep_time
= EMACS_SECS (*timeout
) * 60 +
863 ((EMACS_USECS (*timeout
) * 60) / 1000000);
865 /* Can only handle wait for keyboard input. */
866 if (n
> 1 || wfds
|| efds
)
869 /* Also return true if an event other than a keyDown has occurred.
870 This causes kbd_buffer_get_event in keyboard.c to call
871 read_avail_input which in turn calls XTread_socket to poll for
872 these events. Otherwise these never get processed except but a
873 very slow poll timer. */
874 if (FD_ISSET (0, rfds
) && mac_wait_next_event (&e
, sleep_time
, false))
878 #endif /* not TARGET_API_MAC_CARBON */
882 /* Called in sys_select to wait for an alarm signal to arrive. */
890 if (!target_ticks
) /* no alarm pending */
893 if ((tick
= TickCount ()) < target_ticks
)
894 WaitNextEvent (0, &e
, target_ticks
- tick
, NULL
); /* Accept no event;
895 just wait. by T.I. */
898 if (alarm_signal_func
)
899 (*alarm_signal_func
)(SIGALRM
);
908 long remaining
= target_ticks
? (TickCount () - target_ticks
) / 60 : 0;
910 target_ticks
= seconds
? TickCount () + 60 * seconds
: 0;
912 return (remaining
< 0) ? 0 : (unsigned int) remaining
;
918 extern __sigfun
signal (int signal
, __sigfun signal_func
);
920 sys_signal (int signal_num
, __sigfun signal_func
)
922 extern __signal_func_ptr
signal (int signal
, __signal_func_ptr signal_func
);
924 sys_signal (int signal_num
, __signal_func_ptr signal_func
)
925 #else /* not __MRC__ and not __MWERKS__ */
927 #endif /* not __MRC__ and not __MWERKS__ */
929 if (signal_num
!= SIGALRM
)
930 return signal (signal_num
, signal_func
);
934 __sigfun old_signal_func
;
936 __signal_func_ptr old_signal_func
;
940 old_signal_func
= alarm_signal_func
;
941 alarm_signal_func
= signal_func
;
942 return old_signal_func
;
947 /* gettimeofday should return the amount of time (in a timeval
948 structure) since midnight today. The toolbox function Microseconds
949 returns the number of microseconds (in a UnsignedWide value) since
950 the machine was booted. Also making this complicated is WideAdd,
951 WideSubtract, etc. take wide values. */
958 static wide wall_clock_at_epoch
, clicks_at_epoch
;
959 UnsignedWide uw_microseconds
;
961 time_t sys_time (time_t *);
963 /* If this function is called for the first time, record the number
964 of seconds since midnight and the number of microseconds since
965 boot at the time of this first call. */
970 systime
= sys_time (NULL
);
971 /* Store microseconds since midnight in wall_clock_at_epoch. */
972 WideMultiply (systime
, 1000000L, &wall_clock_at_epoch
);
973 Microseconds (&uw_microseconds
);
974 /* Store microseconds since boot in clicks_at_epoch. */
975 clicks_at_epoch
.hi
= uw_microseconds
.hi
;
976 clicks_at_epoch
.lo
= uw_microseconds
.lo
;
979 /* Get time since boot */
980 Microseconds (&uw_microseconds
);
982 /* Convert to time since midnight*/
983 w_microseconds
.hi
= uw_microseconds
.hi
;
984 w_microseconds
.lo
= uw_microseconds
.lo
;
985 WideSubtract (&w_microseconds
, &clicks_at_epoch
);
986 WideAdd (&w_microseconds
, &wall_clock_at_epoch
);
987 tp
->tv_sec
= WideDivide (&w_microseconds
, 1000000L, &tp
->tv_usec
);
995 sleep (unsigned int seconds
)
997 unsigned long time_up
;
1000 time_up
= TickCount () + seconds
* 60;
1001 while (TickCount () < time_up
)
1003 /* Accept no event; just wait. by T.I. */
1004 WaitNextEvent (0, &e
, 30, NULL
);
1009 #endif /* __MRC__ */
1012 /* The time functions adjust time values according to the difference
1013 between the Unix and CW epoches. */
1016 extern struct tm
*gmtime (const time_t *);
1018 sys_gmtime (const time_t *timer
)
1020 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
1022 return gmtime (&unix_time
);
1027 extern struct tm
*localtime (const time_t *);
1029 sys_localtime (const time_t *timer
)
1031 #if __MSL__ >= 0x6000
1032 time_t unix_time
= *timer
;
1034 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
1037 return localtime (&unix_time
);
1042 extern char *ctime (const time_t *);
1044 sys_ctime (const time_t *timer
)
1046 #if __MSL__ >= 0x6000
1047 time_t unix_time
= *timer
;
1049 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
1052 return ctime (&unix_time
);
1057 extern time_t time (time_t *);
1059 sys_time (time_t *timer
)
1061 #if __MSL__ >= 0x6000
1062 time_t mac_time
= time (NULL
);
1064 time_t mac_time
= time (NULL
) - CW_OR_MPW_UNIX_EPOCH_DIFF
;
1074 /* MPW strftime broken for "%p" format */
1079 sys_strftime (char * s
, size_t maxsize
, const char * format
,
1080 const struct tm
* timeptr
)
1082 if (strcmp (format
, "%p") == 0)
1086 if (timeptr
->tm_hour
< 12)
1098 return strftime (s
, maxsize
, format
, timeptr
);
1100 #endif /* __MRC__ */
1103 /* no subprocesses, empty wait */
1113 croak (char *badfunc
)
1115 printf ("%s not yet implemented\r\n", badfunc
);
1121 index (const char * str
, int chr
)
1123 return strchr (str
, chr
);
1128 mktemp (char *template)
1133 len
= strlen (template);
1135 while (k
>= 0 && template[k
] == 'X')
1138 k
++; /* make k index of first 'X' */
1142 /* Zero filled, number of digits equal to the number of X's. */
1143 sprintf (&template[k
], "%0*d", len
-k
, seqnum
++);
1152 /* Emulate getpwuid, getpwnam and others. */
1154 #define PASSWD_FIELD_SIZE 256
1156 static char my_passwd_name
[PASSWD_FIELD_SIZE
];
1157 static char my_passwd_dir
[MAXPATHLEN
+1];
1159 static struct passwd my_passwd
=
1165 static struct group my_group
=
1167 /* There are no groups on the mac, so we just return "root" as the
1173 /* Initialized by main () in macterm.c to pathname of emacs directory. */
1175 char emacs_passwd_dir
[MAXPATHLEN
+1];
1181 init_emacs_passwd_dir ()
1185 if (getwd (emacs_passwd_dir
) && getwd (my_passwd_dir
))
1187 /* Need pathname of first ancestor that begins with "emacs"
1188 since Mac emacs application is somewhere in the emacs-*
1190 int len
= strlen (emacs_passwd_dir
);
1192 /* j points to the "/" following the directory name being
1195 while (i
>= 0 && !found
)
1197 while (i
>= 0 && emacs_passwd_dir
[i
] != '/')
1199 if (emacs_passwd_dir
[i
] == '/' && i
+5 < len
)
1200 found
= (strncmp (&(emacs_passwd_dir
[i
+1]), "emacs", 5) == 0);
1202 emacs_passwd_dir
[j
+1] = '\0';
1213 /* Setting to "/" probably won't work but set it to something
1215 strcpy (emacs_passwd_dir
, "/");
1216 strcpy (my_passwd_dir
, "/");
1221 static struct passwd emacs_passwd
=
1227 static int my_passwd_inited
= 0;
1235 /* Note: my_passwd_dir initialized in int_emacs_passwd_dir to
1236 directory where Emacs was started. */
1238 owner_name
= (char **) GetResource ('STR ',-16096);
1242 BlockMove ((unsigned char *) *owner_name
,
1243 (unsigned char *) my_passwd_name
,
1245 HUnlock (owner_name
);
1246 p2cstr ((unsigned char *) my_passwd_name
);
1249 my_passwd_name
[0] = 0;
1254 getpwuid (uid_t uid
)
1256 if (!my_passwd_inited
)
1259 my_passwd_inited
= 1;
1267 getgrgid (gid_t gid
)
1274 getpwnam (const char *name
)
1276 if (strcmp (name
, "emacs") == 0)
1277 return &emacs_passwd
;
1279 if (!my_passwd_inited
)
1282 my_passwd_inited
= 1;
1289 /* The functions fork, kill, sigsetmask, sigblock, request_sigio,
1290 setpgrp, setpriority, and unrequest_sigio are defined to be empty
1311 error ("Can't spawn subshell");
1330 request_sigio (void)
1336 unrequest_sigio (void)
1351 pipe (int _fildes
[2])
1358 /* Hard and symbolic links. */
1361 symlink (const char *name1
, const char *name2
)
1369 link (const char *name1
, const char *name2
)
1375 #endif /* ! MAC_OSX */
1377 /* Determine the path name of the file specified by VREFNUM, DIRID,
1378 and NAME and place that in the buffer PATH of length
1381 path_from_vol_dir_name (char *path
, int man_path_len
, short vol_ref_num
,
1382 long dir_id
, ConstStr255Param name
)
1388 if (strlen (name
) > man_path_len
)
1391 memcpy (dir_name
, name
, name
[0]+1);
1392 memcpy (path
, name
, name
[0]+1);
1395 cipb
.dirInfo
.ioDrParID
= dir_id
;
1396 cipb
.dirInfo
.ioNamePtr
= dir_name
;
1400 cipb
.dirInfo
.ioVRefNum
= vol_ref_num
;
1401 cipb
.dirInfo
.ioFDirIndex
= -1;
1402 cipb
.dirInfo
.ioDrDirID
= cipb
.dirInfo
.ioDrParID
;
1403 /* go up to parent each time */
1405 err
= PBGetCatInfo (&cipb
, false);
1410 if (strlen (dir_name
) + strlen (path
) + 1 >= man_path_len
)
1413 strcat (dir_name
, ":");
1414 strcat (dir_name
, path
);
1415 /* attach to front since we're going up directory tree */
1416 strcpy (path
, dir_name
);
1418 while (cipb
.dirInfo
.ioDrDirID
!= fsRtDirID
);
1419 /* stop when we see the volume's root directory */
1421 return 1; /* success */
1427 readlink (const char *path
, char *buf
, int bufsiz
)
1429 char mac_sym_link_name
[MAXPATHLEN
+1];
1432 Boolean target_is_folder
, was_aliased
;
1433 Str255 directory_name
, mac_pathname
;
1436 if (posix_to_mac_pathname (path
, mac_sym_link_name
, MAXPATHLEN
+1) == 0)
1439 c2pstr (mac_sym_link_name
);
1440 err
= FSMakeFSSpec (0, 0, mac_sym_link_name
, &fsspec
);
1447 err
= ResolveAliasFile (&fsspec
, true, &target_is_folder
, &was_aliased
);
1448 if (err
!= noErr
|| !was_aliased
)
1454 if (path_from_vol_dir_name (mac_pathname
, 255, fsspec
.vRefNum
, fsspec
.parID
,
1461 if (mac_to_posix_pathname (mac_pathname
, buf
, bufsiz
) == 0)
1467 return strlen (buf
);
1471 /* Convert a path to one with aliases fully expanded. */
1474 find_true_pathname (const char *path
, char *buf
, int bufsiz
)
1476 char *q
, temp
[MAXPATHLEN
+1];
1480 if (bufsiz
<= 0 || path
== 0 || path
[0] == '\0')
1487 q
= strchr (p
+ 1, '/');
1489 q
= strchr (p
, '/');
1490 len
= 0; /* loop may not be entered, e.g., for "/" */
1495 strncat (temp
, p
, q
- p
);
1496 len
= readlink (temp
, buf
, bufsiz
);
1499 if (strlen (temp
) + 1 > bufsiz
)
1509 if (len
+ strlen (p
) + 1 >= bufsiz
)
1513 return len
+ strlen (p
);
1518 umask (mode_t numask
)
1520 static mode_t mask
= 022;
1521 mode_t oldmask
= mask
;
1528 chmod (const char *path
, mode_t mode
)
1530 /* say it always succeed for now */
1539 return fcntl (oldd
, F_DUPFD
, 0);
1541 /* current implementation of fcntl in fcntl.mac.c simply returns old
1543 return fcntl (oldd
, F_DUPFD
);
1550 /* This is from the original sysdep.c. Emulate BSD dup2. First close
1551 newd if it already exists. Then, attempt to dup oldd. If not
1552 successful, call dup2 recursively until we are, then close the
1553 unsuccessful ones. */
1556 dup2 (int oldd
, int newd
)
1567 ret
= dup2 (oldd
, newd
);
1573 /* let it fail for now */
1590 ioctl (int d
, int request
, void *argp
)
1600 if (fildes
>=0 && fildes
<= 2)
1633 #endif /* __MRC__ */
1637 #if __MSL__ < 0x6000
1645 #endif /* __MWERKS__ */
1647 #endif /* ! MAC_OSX */
1650 /* Return the path to the directory in which Emacs can create
1651 temporary files. The MacOS "temporary items" directory cannot be
1652 used because it removes the file written by a process when it
1653 exits. In that sense it's more like "/dev/null" than "/tmp" (but
1654 again not exactly). And of course Emacs needs to read back the
1655 files written by its subprocesses. So here we write the files to a
1656 directory "Emacs" in the Preferences Folder. This directory is
1657 created if it does not exist. */
1660 get_temp_dir_name ()
1662 static char *temp_dir_name
= NULL
;
1666 Str255 dir_name
, full_path
;
1668 char unix_dir_name
[MAXPATHLEN
+1];
1671 /* Cache directory name with pointer temp_dir_name.
1672 Look for it only the first time. */
1675 err
= FindFolder (kOnSystemDisk
, kPreferencesFolderType
, kCreateFolder
,
1676 &vol_ref_num
, &dir_id
);
1680 if (!path_from_vol_dir_name (full_path
, 255, vol_ref_num
, dir_id
, "\p"))
1683 if (strlen (full_path
) + 6 <= MAXPATHLEN
)
1684 strcat (full_path
, "Emacs:");
1688 if (!mac_to_posix_pathname (full_path
, unix_dir_name
, MAXPATHLEN
+1))
1691 dir
= opendir (unix_dir_name
); /* check whether temp directory exists */
1694 else if (mkdir (unix_dir_name
, 0700) != 0) /* create it if not */
1697 temp_dir_name
= (char *) malloc (strlen (unix_dir_name
) + 1);
1698 strcpy (temp_dir_name
, unix_dir_name
);
1701 return temp_dir_name
;
1706 /* Allocate and construct an array of pointers to strings from a list
1707 of strings stored in a 'STR#' resource. The returned pointer array
1708 is stored in the style of argv and environ: if the 'STR#' resource
1709 contains numString strings, a pointer array with numString+1
1710 elements is returned in which the last entry contains a null
1711 pointer. The pointer to the pointer array is passed by pointer in
1712 parameter t. The resource ID of the 'STR#' resource is passed in
1713 parameter StringListID.
1717 get_string_list (char ***t
, short string_list_id
)
1723 h
= GetResource ('STR#', string_list_id
);
1728 num_strings
= * (short *) p
;
1730 *t
= (char **) malloc (sizeof (char *) * (num_strings
+ 1));
1731 for (i
= 0; i
< num_strings
; i
++)
1733 short length
= *p
++;
1734 (*t
)[i
] = (char *) malloc (length
+ 1);
1735 strncpy ((*t
)[i
], p
, length
);
1736 (*t
)[i
][length
] = '\0';
1739 (*t
)[num_strings
] = 0;
1744 /* Return no string in case GetResource fails. Bug fixed by
1745 Ikegami Tsutomu. Caused MPW build to crash without sym -on
1746 option (no sym -on implies -opt local). */
1747 *t
= (char **) malloc (sizeof (char *));
1754 get_path_to_system_folder ()
1759 Str255 dir_name
, full_path
;
1761 static char system_folder_unix_name
[MAXPATHLEN
+1];
1764 err
= FindFolder (kOnSystemDisk
, kSystemFolderType
, kDontCreateFolder
,
1765 &vol_ref_num
, &dir_id
);
1769 if (!path_from_vol_dir_name (full_path
, 255, vol_ref_num
, dir_id
, "\p"))
1772 if (!mac_to_posix_pathname (full_path
, system_folder_unix_name
,
1776 return system_folder_unix_name
;
1782 #define ENVIRON_STRING_LIST_ID 128
1784 /* Get environment variable definitions from STR# resource. */
1791 get_string_list (&environ
, ENVIRON_STRING_LIST_ID
);
1797 /* Make HOME directory the one Emacs starts up in if not specified
1799 if (getenv ("HOME") == NULL
)
1801 environ
= (char **) realloc (environ
, sizeof (char *) * (i
+ 2));
1804 environ
[i
] = (char *) malloc (strlen (my_passwd_dir
) + 6);
1807 strcpy (environ
[i
], "HOME=");
1808 strcat (environ
[i
], my_passwd_dir
);
1815 /* Make HOME directory the one Emacs starts up in if not specified
1817 if (getenv ("MAIL") == NULL
)
1819 environ
= (char **) realloc (environ
, sizeof (char *) * (i
+ 2));
1822 char * path_to_system_folder
= get_path_to_system_folder ();
1823 environ
[i
] = (char *) malloc (strlen (path_to_system_folder
) + 22);
1826 strcpy (environ
[i
], "MAIL=");
1827 strcat (environ
[i
], path_to_system_folder
);
1828 strcat (environ
[i
], "Eudora Folder/In");
1836 /* Return the value of the environment variable NAME. */
1839 getenv (const char *name
)
1841 int length
= strlen(name
);
1844 for (e
= environ
; *e
!= 0; e
++)
1845 if (strncmp(*e
, name
, length
) == 0 && (*e
)[length
] == '=')
1846 return &(*e
)[length
+ 1];
1848 if (strcmp (name
, "TMPDIR") == 0)
1849 return get_temp_dir_name ();
1856 /* see Interfaces&Libraries:Interfaces:CIncludes:signal.h */
1857 char *sys_siglist
[] =
1859 "Zero is not a signal!!!",
1861 "Interactive user interrupt", /* 2 */ "?",
1862 "Floating point exception", /* 4 */ "?", "?", "?",
1863 "Illegal instruction", /* 8 */ "?", "?", "?", "?", "?", "?", "?",
1864 "Segment violation", /* 16 */ "?", "?", "?", "?", "?", "?", "?",
1865 "?", "?", "?", "?", "?", "?", "?", "?",
1869 char *sys_siglist
[] =
1871 "Zero is not a signal!!!",
1873 "Floating point exception",
1874 "Illegal instruction",
1875 "Interactive user interrupt",
1876 "Segment violation",
1879 #else /* not __MRC__ and not __MWERKS__ */
1881 #endif /* not __MRC__ and not __MWERKS__ */
1884 #include <utsname.h>
1887 uname (struct utsname
*name
)
1890 system_name
= GetString (-16413); /* IM - Resource Manager Reference */
1893 BlockMove (*system_name
, name
->nodename
, (*system_name
)[0]+1);
1894 p2cstr (name
->nodename
);
1902 #include <Processes.h>
1905 /* Event class of HLE sent to subprocess. */
1906 const OSType kEmacsSubprocessSend
= 'ESND';
1908 /* Event class of HLE sent back from subprocess. */
1909 const OSType kEmacsSubprocessReply
= 'ERPY';
1913 mystrchr (char *s
, char c
)
1915 while (*s
&& *s
!= c
)
1943 mystrcpy (char *to
, char *from
)
1955 /* Start a Mac subprocess. Arguments for it is passed in argv (null
1956 terminated). The process should run with the default directory
1957 "workdir", read input from "infn", and write output and error to
1958 "outfn" and "errfn", resp. The Process Manager call
1959 LaunchApplication is used to start the subprocess. We use high
1960 level events as the mechanism to pass arguments to the subprocess
1961 and to make Emacs wait for the subprocess to terminate and pass
1962 back a result code. The bulk of the code here packs the arguments
1963 into one message to be passed together with the high level event.
1964 Emacs also sometimes starts a subprocess using a shell to perform
1965 wildcard filename expansion. Since we don't really have a shell on
1966 the Mac, this case is detected and the starting of the shell is
1967 by-passed. We really need to add code here to do filename
1968 expansion to support such functionality. */
1971 run_mac_command (argv
, workdir
, infn
, outfn
, errfn
)
1972 unsigned char **argv
;
1973 const char *workdir
;
1974 const char *infn
, *outfn
, *errfn
;
1976 #if TARGET_API_MAC_CARBON
1978 #else /* not TARGET_API_MAC_CARBON */
1979 char macappname
[MAXPATHLEN
+1], macworkdir
[MAXPATHLEN
+1];
1980 char macinfn
[MAXPATHLEN
+1], macoutfn
[MAXPATHLEN
+1], macerrfn
[MAXPATHLEN
+1];
1981 int paramlen
, argc
, newargc
, j
, retries
;
1982 char **newargv
, *param
, *p
;
1985 LaunchParamBlockRec lpbr
;
1986 EventRecord send_event
, reply_event
;
1987 RgnHandle cursor_region_handle
;
1989 unsigned long ref_con
, len
;
1991 if (posix_to_mac_pathname (workdir
, macworkdir
, MAXPATHLEN
+1) == 0)
1993 if (posix_to_mac_pathname (infn
, macinfn
, MAXPATHLEN
+1) == 0)
1995 if (posix_to_mac_pathname (outfn
, macoutfn
, MAXPATHLEN
+1) == 0)
1997 if (posix_to_mac_pathname (errfn
, macerrfn
, MAXPATHLEN
+1) == 0)
2000 paramlen
= strlen (macworkdir
) + strlen (macinfn
) + strlen (macoutfn
)
2001 + strlen (macerrfn
) + 4; /* count nulls at end of strings */
2010 /* If a subprocess is invoked with a shell, we receive 3 arguments
2011 of the form: "<path to emacs bins>/sh" "-c" "<path to emacs
2012 bins>/<command> <command args>" */
2013 j
= strlen (argv
[0]);
2014 if (j
>= 3 && strcmp (argv
[0]+j
-3, "/sh") == 0
2015 && argc
== 3 && strcmp (argv
[1], "-c") == 0)
2017 char *command
, *t
, tempmacpathname
[MAXPATHLEN
+1];
2019 /* The arguments for the command in argv[2] are separated by
2020 spaces. Count them and put the count in newargc. */
2021 command
= (char *) alloca (strlen (argv
[2])+2);
2022 strcpy (command
, argv
[2]);
2023 if (command
[strlen (command
) - 1] != ' ')
2024 strcat (command
, " ");
2028 t
= mystrchr (t
, ' ');
2032 t
= mystrchr (t
+1, ' ');
2035 newargv
= (char **) alloca (sizeof (char *) * newargc
);
2038 for (j
= 0; j
< newargc
; j
++)
2040 newargv
[j
] = (char *) alloca (strlen (t
) + 1);
2041 mystrcpy (newargv
[j
], t
);
2044 paramlen
+= strlen (newargv
[j
]) + 1;
2047 if (strncmp (newargv
[0], "~emacs/", 7) == 0)
2049 if (posix_to_mac_pathname (newargv
[0], tempmacpathname
, MAXPATHLEN
+1)
2054 { /* sometimes Emacs call "sh" without a path for the command */
2056 char *t
= (char *) alloca (strlen (newargv
[0]) + 7 + 1);
2057 strcpy (t
, "~emacs/");
2058 strcat (t
, newargv
[0]);
2061 openp (Vexec_path
, build_string (newargv
[0]), Vexec_suffixes
, &path
,
2062 make_number (X_OK
));
2066 if (posix_to_mac_pathname (SDATA (path
), tempmacpathname
,
2070 strcpy (macappname
, tempmacpathname
);
2074 if (posix_to_mac_pathname (argv
[0], macappname
, MAXPATHLEN
+1) == 0)
2077 newargv
= (char **) alloca (sizeof (char *) * argc
);
2079 for (j
= 1; j
< argc
; j
++)
2081 if (strncmp (argv
[j
], "~emacs/", 7) == 0)
2083 char *t
= strchr (argv
[j
], ' ');
2086 char tempcmdname
[MAXPATHLEN
+1], tempmaccmdname
[MAXPATHLEN
+1];
2087 strncpy (tempcmdname
, argv
[j
], t
-argv
[j
]);
2088 tempcmdname
[t
-argv
[j
]] = '\0';
2089 if (posix_to_mac_pathname (tempcmdname
, tempmaccmdname
,
2092 newargv
[j
] = (char *) alloca (strlen (tempmaccmdname
)
2094 strcpy (newargv
[j
], tempmaccmdname
);
2095 strcat (newargv
[j
], t
);
2099 char tempmaccmdname
[MAXPATHLEN
+1];
2100 if (posix_to_mac_pathname (argv
[j
], tempmaccmdname
,
2103 newargv
[j
] = (char *) alloca (strlen (tempmaccmdname
)+1);
2104 strcpy (newargv
[j
], tempmaccmdname
);
2108 newargv
[j
] = argv
[j
];
2109 paramlen
+= strlen (newargv
[j
]) + 1;
2113 /* After expanding all the arguments, we now know the length of the
2114 parameter block to be sent to the subprocess as a message
2115 attached to the HLE. */
2116 param
= (char *) malloc (paramlen
+ 1);
2122 /* first byte of message contains number of arguments for command */
2123 strcpy (p
, macworkdir
);
2124 p
+= strlen (macworkdir
);
2126 /* null terminate strings sent so it's possible to use strcpy over there */
2127 strcpy (p
, macinfn
);
2128 p
+= strlen (macinfn
);
2130 strcpy (p
, macoutfn
);
2131 p
+= strlen (macoutfn
);
2133 strcpy (p
, macerrfn
);
2134 p
+= strlen (macerrfn
);
2136 for (j
= 1; j
< newargc
; j
++)
2138 strcpy (p
, newargv
[j
]);
2139 p
+= strlen (newargv
[j
]);
2143 c2pstr (macappname
);
2145 iErr
= FSMakeFSSpec (0, 0, macappname
, &spec
);
2153 lpbr
.launchBlockID
= extendedBlock
;
2154 lpbr
.launchEPBLength
= extendedBlockLen
;
2155 lpbr
.launchControlFlags
= launchContinue
+ launchNoFileFlags
;
2156 lpbr
.launchAppSpec
= &spec
;
2157 lpbr
.launchAppParameters
= NULL
;
2159 iErr
= LaunchApplication (&lpbr
); /* call the subprocess */
2166 send_event
.what
= kHighLevelEvent
;
2167 send_event
.message
= kEmacsSubprocessSend
;
2168 /* Event ID stored in "where" unused */
2171 /* OS may think current subprocess has terminated if previous one
2172 terminated recently. */
2175 iErr
= PostHighLevelEvent (&send_event
, &lpbr
.launchProcessSN
, 0, param
,
2176 paramlen
+ 1, receiverIDisPSN
);
2178 while (iErr
== sessClosedErr
&& retries
-- > 0);
2186 cursor_region_handle
= NewRgn ();
2188 /* Wait for the subprocess to finish, when it will send us a ERPY
2189 high level event. */
2191 if (WaitNextEvent (highLevelEventMask
, &reply_event
, 180,
2192 cursor_region_handle
)
2193 && reply_event
.message
== kEmacsSubprocessReply
)
2196 /* The return code is sent through the refCon */
2197 iErr
= AcceptHighLevelEvent (&targ
, &ref_con
, NULL
, &len
);
2200 DisposeHandle ((Handle
) cursor_region_handle
);
2205 DisposeHandle ((Handle
) cursor_region_handle
);
2209 #endif /* not TARGET_API_MAC_CARBON */
2214 opendir (const char *dirname
)
2216 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
2217 char mac_pathname
[MAXPATHLEN
+1], vol_name
[MAXPATHLEN
+1];
2221 int len
, vol_name_len
;
2223 if (find_true_pathname (dirname
, true_pathname
, MAXPATHLEN
+1) == -1)
2226 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
2228 fully_resolved_name
[len
] = '\0';
2230 strcpy (fully_resolved_name
, true_pathname
);
2232 dirp
= (DIR *) malloc (sizeof(DIR));
2236 /* Handle special case when dirname is "/": sets up for readir to
2237 get all mount volumes. */
2238 if (strcmp (fully_resolved_name
, "/") == 0)
2240 dirp
->getting_volumes
= 1; /* special all mounted volumes DIR struct */
2241 dirp
->current_index
= 1; /* index for first volume */
2245 /* Handle typical cases: not accessing all mounted volumes. */
2246 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
2249 /* Emacs calls opendir without the trailing '/', Mac needs trailing ':' */
2250 len
= strlen (mac_pathname
);
2251 if (mac_pathname
[len
- 1] != ':' && len
< MAXPATHLEN
)
2252 strcat (mac_pathname
, ":");
2254 /* Extract volume name */
2255 vol_name_len
= strchr (mac_pathname
, ':') - mac_pathname
;
2256 strncpy (vol_name
, mac_pathname
, vol_name_len
);
2257 vol_name
[vol_name_len
] = '\0';
2258 strcat (vol_name
, ":");
2260 c2pstr (mac_pathname
);
2261 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
2262 /* using full pathname so vRefNum and DirID ignored */
2263 cipb
.hFileInfo
.ioVRefNum
= 0;
2264 cipb
.hFileInfo
.ioDirID
= 0;
2265 cipb
.hFileInfo
.ioFDirIndex
= 0;
2266 /* set to 0 to get information about specific dir or file */
2268 errno
= PBGetCatInfo (&cipb
, false);
2275 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x10)) /* bit 4 = 1 for directories */
2276 return 0; /* not a directory */
2278 dirp
->dir_id
= cipb
.dirInfo
.ioDrDirID
; /* used later in readdir */
2279 dirp
->getting_volumes
= 0;
2280 dirp
->current_index
= 1; /* index for first file/directory */
2283 vpb
.ioNamePtr
= vol_name
;
2284 /* using full pathname so vRefNum and DirID ignored */
2286 vpb
.ioVolIndex
= -1;
2287 errno
= PBHGetVInfo ((union HParamBlockRec
*) &vpb
, false);
2294 dirp
->vol_ref_num
= vpb
.ioVRefNum
;
2311 HParamBlockRec hpblock
;
2313 static struct dirent s_dirent
;
2314 static Str255 s_name
;
2318 /* Handle the root directory containing the mounted volumes. Call
2319 PBHGetVInfo specifying an index to obtain the info for a volume.
2320 PBHGetVInfo returns an error when it receives an index beyond the
2321 last volume, at which time we should return a nil dirent struct
2323 if (dp
->getting_volumes
)
2325 hpblock
.volumeParam
.ioNamePtr
= s_name
;
2326 hpblock
.volumeParam
.ioVRefNum
= 0;
2327 hpblock
.volumeParam
.ioVolIndex
= dp
->current_index
;
2329 errno
= PBHGetVInfo (&hpblock
, false);
2337 strcat (s_name
, "/"); /* need "/" for stat to work correctly */
2339 dp
->current_index
++;
2341 s_dirent
.d_ino
= hpblock
.volumeParam
.ioVRefNum
;
2342 s_dirent
.d_name
= s_name
;
2348 cipb
.hFileInfo
.ioVRefNum
= dp
->vol_ref_num
;
2349 cipb
.hFileInfo
.ioNamePtr
= s_name
;
2350 /* location to receive filename returned */
2352 /* return only visible files */
2356 cipb
.hFileInfo
.ioDirID
= dp
->dir_id
;
2357 /* directory ID found by opendir */
2358 cipb
.hFileInfo
.ioFDirIndex
= dp
->current_index
;
2360 errno
= PBGetCatInfo (&cipb
, false);
2367 /* insist on a visible entry */
2368 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* directory? */
2369 done
= !(cipb
.dirInfo
.ioDrUsrWds
.frFlags
& fInvisible
);
2371 done
= !(cipb
.hFileInfo
.ioFlFndrInfo
.fdFlags
& fInvisible
);
2373 dp
->current_index
++;
2386 s_dirent
.d_ino
= cipb
.dirInfo
.ioDrDirID
;
2387 /* value unimportant: non-zero for valid file */
2388 s_dirent
.d_name
= s_name
;
2398 char mac_pathname
[MAXPATHLEN
+1];
2399 Str255 directory_name
;
2403 if (path_from_vol_dir_name (mac_pathname
, 255, 0, 0, "\p") == 0)
2406 if (mac_to_posix_pathname (mac_pathname
, path
, MAXPATHLEN
+1) == 0)
2412 #endif /* ! MAC_OSX */
2416 initialize_applescript ()
2421 /* if open fails, as_scripting_component is set to NULL. Its
2422 subsequent use in OSA calls will fail with badComponentInstance
2424 as_scripting_component
= OpenDefaultComponent (kOSAComponentType
,
2425 kAppleScriptSubtype
);
2427 null_desc
.descriptorType
= typeNull
;
2428 null_desc
.dataHandle
= 0;
2429 osaerror
= OSAMakeContext (as_scripting_component
, &null_desc
,
2430 kOSANullScript
, &as_script_context
);
2432 as_script_context
= kOSANullScript
;
2433 /* use default context if create fails */
2437 void terminate_applescript()
2439 OSADispose (as_scripting_component
, as_script_context
);
2440 CloseComponent (as_scripting_component
);
2444 /* Compile and execute the AppleScript SCRIPT and return the error
2445 status as function value. A zero is returned if compilation and
2446 execution is successful, in which case RESULT returns a pointer to
2447 a string containing the resulting script value. Otherwise, the Mac
2448 error code is returned and RESULT returns a pointer to an error
2449 string. In both cases the caller should deallocate the storage
2450 used by the string pointed to by RESULT if it is non-NULL. For
2451 documentation on the MacOS scripting architecture, see Inside
2452 Macintosh - Interapplication Communications: Scripting Components. */
2455 do_applescript (char *script
, char **result
)
2457 AEDesc script_desc
, result_desc
, error_desc
;
2464 if (!as_scripting_component
)
2465 initialize_applescript();
2467 error
= AECreateDesc (typeChar
, script
, strlen(script
), &script_desc
);
2471 osaerror
= OSADoScript (as_scripting_component
, &script_desc
, kOSANullScript
,
2472 typeChar
, kOSAModeNull
, &result_desc
);
2474 if (osaerror
== errOSAScriptError
)
2476 /* error executing AppleScript: retrieve error message */
2477 if (!OSAScriptError (as_scripting_component
, kOSAErrorMessage
, typeChar
,
2480 #if TARGET_API_MAC_CARBON
2481 length
= AEGetDescDataSize (&error_desc
);
2482 *result
= (char *) xmalloc (length
+ 1);
2485 AEGetDescData (&error_desc
, *result
, length
);
2486 *(*result
+ length
) = '\0';
2488 #else /* not TARGET_API_MAC_CARBON */
2489 HLock (error_desc
.dataHandle
);
2490 length
= GetHandleSize(error_desc
.dataHandle
);
2491 *result
= (char *) xmalloc (length
+ 1);
2494 memcpy (*result
, *(error_desc
.dataHandle
), length
);
2495 *(*result
+ length
) = '\0';
2497 HUnlock (error_desc
.dataHandle
);
2498 #endif /* not TARGET_API_MAC_CARBON */
2499 AEDisposeDesc (&error_desc
);
2502 else if (osaerror
== noErr
) /* success: retrieve resulting script value */
2504 #if TARGET_API_MAC_CARBON
2505 length
= AEGetDescDataSize (&result_desc
);
2506 *result
= (char *) xmalloc (length
+ 1);
2509 AEGetDescData (&result_desc
, *result
, length
);
2510 *(*result
+ length
) = '\0';
2512 #else /* not TARGET_API_MAC_CARBON */
2513 HLock (result_desc
.dataHandle
);
2514 length
= GetHandleSize(result_desc
.dataHandle
);
2515 *result
= (char *) xmalloc (length
+ 1);
2518 memcpy (*result
, *(result_desc
.dataHandle
), length
);
2519 *(*result
+ length
) = '\0';
2521 HUnlock (result_desc
.dataHandle
);
2522 #endif /* not TARGET_API_MAC_CARBON */
2523 AEDisposeDesc (&result_desc
);
2526 AEDisposeDesc (&script_desc
);
2532 DEFUN ("do-applescript", Fdo_applescript
, Sdo_applescript
, 1, 1, 0,
2533 doc
: /* Compile and execute AppleScript SCRIPT and retrieve and return the result.
2534 If compilation and execution are successful, the resulting script
2535 value is returned as a string. Otherwise the function aborts and
2536 displays the error message returned by the AppleScript scripting
2541 char *result
, *temp
;
2542 Lisp_Object lisp_result
;
2545 CHECK_STRING (script
);
2548 status
= do_applescript (SDATA (script
), &result
);
2553 error ("AppleScript error %d", status
);
2556 /* Unfortunately only OSADoScript in do_applescript knows how
2557 how large the resulting script value or error message is
2558 going to be and therefore as caller memory must be
2559 deallocated here. It is necessary to free the error
2560 message before calling error to avoid a memory leak. */
2561 temp
= (char *) alloca (strlen (result
) + 1);
2562 strcpy (temp
, result
);
2569 lisp_result
= build_string (result
);
2576 DEFUN ("mac-file-name-to-posix", Fmac_file_name_to_posix
,
2577 Smac_file_name_to_posix
, 1, 1, 0,
2578 doc
: /* Convert Macintosh filename to Posix form. */)
2580 Lisp_Object mac_filename
;
2582 char posix_filename
[MAXPATHLEN
+1];
2584 CHECK_STRING (mac_filename
);
2586 if (mac_to_posix_pathname (SDATA (mac_filename
), posix_filename
,
2588 return build_string (posix_filename
);
2594 DEFUN ("posix-file-name-to-mac", Fposix_file_name_to_mac
,
2595 Sposix_file_name_to_mac
, 1, 1, 0,
2596 doc
: /* Convert Posix filename to Mac form. */)
2598 Lisp_Object posix_filename
;
2600 char mac_filename
[MAXPATHLEN
+1];
2602 CHECK_STRING (posix_filename
);
2604 if (posix_to_mac_pathname (SDATA (posix_filename
), mac_filename
,
2606 return build_string (mac_filename
);
2612 /* set interprogram-paste-function to mac-paste-function in mac-win.el
2613 to enable Emacs to obtain the contents of the Mac clipboard. */
2614 DEFUN ("mac-paste-function", Fmac_paste_function
, Smac_paste_function
, 0, 0, 0,
2615 doc
: /* Return the contents of the Mac clipboard as a string. */)
2618 #if TARGET_API_MAC_CARBON
2621 ScrapFlavorFlags sff
;
2627 err
= GetCurrentScrap (&scrap
);
2629 err
= GetScrapFlavorFlags (scrap
, kScrapFlavorTypeText
, &sff
);
2631 err
= GetScrapFlavorSize (scrap
, kScrapFlavorTypeText
, &s
);
2632 if (err
== noErr
&& (data
= (char*) alloca (s
)))
2633 err
= GetScrapFlavorData (scrap
, kScrapFlavorTypeText
, &s
, data
);
2635 if (err
!= noErr
|| s
== 0)
2638 /* Emacs expects clipboard contents have Unix-style eol's */
2639 for (i
= 0; i
< s
; i
++)
2640 if (data
[i
] == '\r')
2643 return make_string (data
, s
);
2644 #else /* not TARGET_API_MAC_CARBON */
2647 long scrap_offset
, rc
, i
;
2649 my_handle
= NewHandle (0); /* allocate 0-length data area */
2651 rc
= GetScrap (my_handle
, 'TEXT', &scrap_offset
);
2657 /* Emacs expects clipboard contents have Unix-style eol's */
2658 for (i
= 0; i
< rc
; i
++)
2659 if ((*my_handle
)[i
] == '\r')
2660 (*my_handle
)[i
] = '\n';
2662 value
= make_string (*my_handle
, rc
);
2664 HUnlock (my_handle
);
2666 DisposeHandle (my_handle
);
2669 #endif /* not TARGET_API_MAC_CARBON */
2673 /* set interprogram-cut-function to mac-cut-function in mac-win.el
2674 to enable Emacs to write the top of the kill-ring to the Mac clipboard. */
2675 DEFUN ("mac-cut-function", Fmac_cut_function
, Smac_cut_function
, 1, 2, 0,
2676 doc
: /* Put the value of the string parameter to the Mac clipboard. */)
2678 Lisp_Object value
, push
;
2683 /* fixme: ignore the push flag for now */
2685 CHECK_STRING (value
);
2687 len
= SCHARS (value
);
2688 buf
= (char *) alloca (len
+1);
2689 bcopy (SDATA (value
), buf
, len
);
2692 /* convert to Mac-style eol's before sending to clipboard */
2693 for (i
= 0; i
< len
; i
++)
2697 #if TARGET_API_MAC_CARBON
2702 ClearCurrentScrap ();
2703 if (GetCurrentScrap (&scrap
) != noErr
)
2706 error ("cannot get current scrap");
2709 if (PutScrapFlavor (scrap
, kScrapFlavorTypeText
, kScrapFlavorMaskNone
, len
,
2713 error ("cannot put to scrap");
2717 #else /* not TARGET_API_MAC_CARBON */
2719 PutScrap (len
, 'TEXT', buf
);
2720 #endif /* not TARGET_API_MAC_CARBON */
2726 DEFUN ("x-selection-exists-p", Fx_selection_exists_p
, Sx_selection_exists_p
,
2728 doc
: /* Whether there is an owner for the given X Selection.
2729 The arg should be the name of the selection in question, typically one of
2730 the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.
2731 \(Those are literal upper-case symbol names, since that's what X expects.)
2732 For convenience, the symbol nil is the same as `PRIMARY',
2733 and t is the same as `SECONDARY'. */)
2735 Lisp_Object selection
;
2737 CHECK_SYMBOL (selection
);
2739 /* Return nil for PRIMARY and SECONDARY selections; for CLIPBOARD, check
2740 if the clipboard currently has valid text format contents. */
2742 if (EQ (selection
, QCLIPBOARD
))
2744 Lisp_Object val
= Qnil
;
2746 #if TARGET_API_MAC_CARBON
2748 ScrapFlavorFlags sff
;
2751 if (GetCurrentScrap (&scrap
) == noErr
)
2752 if (GetScrapFlavorFlags (scrap
, kScrapFlavorTypeText
, &sff
) == noErr
)
2755 #else /* not TARGET_API_MAC_CARBON */
2757 long rc
, scrap_offset
;
2759 my_handle
= NewHandle (0);
2761 rc
= GetScrap (my_handle
, 'TEXT', &scrap_offset
);
2765 DisposeHandle (my_handle
);
2766 #endif /* not TARGET_API_MAC_CARBON */
2773 extern void mac_clear_font_name_table
P_ ((void));
2775 DEFUN ("mac-clear-font-name-table", Fmac_clear_font_name_table
, Smac_clear_font_name_table
, 0, 0, 0,
2776 doc
: /* Clear the font name table. */)
2780 mac_clear_font_name_table ();
2787 extern int inhibit_window_system
;
2788 extern int noninteractive
;
2790 /* Unlike in X11, window events in Carbon do not come from sockets.
2791 So we cannot simply use `select' to monitor two kinds of inputs:
2792 window events and process outputs. We emulate such functionality
2793 by regarding fd 0 as the window event channel and simultaneously
2794 monitoring both kinds of input channels. It is implemented by
2795 dividing into some cases:
2796 1. The window event channel is not involved.
2798 2. Sockets are not involved.
2799 -> Use ReceiveNextEvent.
2800 3. [If SELECT_USE_CFSOCKET is defined]
2801 Only the window event channel and socket read channels are
2802 involved, and timeout is not too short (greater than
2803 SELECT_TIMEOUT_THRESHHOLD_RUNLOOP seconds).
2804 -> Create CFSocket for each socket and add it into the current
2805 event RunLoop so that an `ready-to-read' event can be posted
2806 to the event queue that is also used for window events. Then
2807 ReceiveNextEvent can wait for both kinds of inputs.
2809 -> Periodically poll the window input channel while repeatedly
2810 executing `select' with a short timeout
2811 (SELECT_POLLING_PERIOD_USEC microseconds). */
2813 #define SELECT_POLLING_PERIOD_USEC 20000
2814 #ifdef SELECT_USE_CFSOCKET
2815 #define SELECT_TIMEOUT_THRESHOLD_RUNLOOP 0.2
2816 #define EVENT_CLASS_SOCK 'Sock'
2819 socket_callback (s
, type
, address
, data
, info
)
2821 CFSocketCallBackType type
;
2828 CreateEvent (NULL
, EVENT_CLASS_SOCK
, 0, 0, kEventAttributeNone
, &event
);
2829 PostEventToQueue (GetCurrentEventQueue (), event
, kEventPriorityStandard
);
2830 ReleaseEvent (event
);
2832 #endif /* SELECT_USE_CFSOCKET */
2835 select_and_poll_event (n
, rfds
, wfds
, efds
, timeout
)
2840 struct timeval
*timeout
;
2845 r
= select (n
, rfds
, wfds
, efds
, timeout
);
2849 err
= ReceiveNextEvent (0, NULL
, kEventDurationNoWait
,
2850 kEventLeaveInQueue
, NULL
);
2861 #ifndef MAC_OS_X_VERSION_10_2
2862 #undef SELECT_INVALIDATE_CFSOCKET
2866 sys_select (n
, rfds
, wfds
, efds
, timeout
)
2871 struct timeval
*timeout
;
2875 EMACS_TIME select_timeout
;
2877 if (inhibit_window_system
|| noninteractive
2878 || rfds
== NULL
|| !FD_ISSET (0, rfds
))
2879 return select (n
, rfds
, wfds
, efds
, timeout
);
2883 if (wfds
== NULL
&& efds
== NULL
)
2886 SELECT_TYPE orfds
= *rfds
;
2888 EventTimeout timeout_sec
=
2890 ? (EMACS_SECS (*timeout
) * kEventDurationSecond
2891 + EMACS_USECS (*timeout
) * kEventDurationMicrosecond
)
2892 : kEventDurationForever
);
2894 for (i
= 1; i
< n
; i
++)
2895 if (FD_ISSET (i
, rfds
))
2901 err
= ReceiveNextEvent (0, NULL
, timeout_sec
,
2902 kEventLeaveInQueue
, NULL
);
2913 /* Avoid initial overhead of RunLoop setup for the case that
2914 some input is already available. */
2915 EMACS_SET_SECS_USECS (select_timeout
, 0, 0);
2916 r
= select_and_poll_event (n
, rfds
, wfds
, efds
, &select_timeout
);
2917 if (r
!= 0 || timeout_sec
== 0.0)
2922 #ifdef SELECT_USE_CFSOCKET
2923 if (timeout_sec
> 0 && timeout_sec
<= SELECT_TIMEOUT_THRESHOLD_RUNLOOP
)
2924 goto poll_periodically
;
2927 CFRunLoopRef runloop
=
2928 (CFRunLoopRef
) GetCFRunLoopFromEventLoop (GetCurrentEventLoop ());
2929 EventTypeSpec specs
[] = {{EVENT_CLASS_SOCK
, 0}};
2930 #ifdef SELECT_INVALIDATE_CFSOCKET
2931 CFSocketRef
*shead
, *s
;
2933 CFRunLoopSourceRef
*shead
, *s
;
2938 #ifdef SELECT_INVALIDATE_CFSOCKET
2939 shead
= xmalloc (sizeof (CFSocketRef
) * nsocks
);
2941 shead
= xmalloc (sizeof (CFRunLoopSourceRef
) * nsocks
);
2944 for (i
= 1; i
< n
; i
++)
2945 if (FD_ISSET (i
, rfds
))
2947 CFSocketRef socket
=
2948 CFSocketCreateWithNative (NULL
, i
, kCFSocketReadCallBack
,
2949 socket_callback
, NULL
);
2950 CFRunLoopSourceRef source
=
2951 CFSocketCreateRunLoopSource (NULL
, socket
, 0);
2953 #ifdef SELECT_INVALIDATE_CFSOCKET
2954 CFSocketSetSocketFlags (socket
, 0);
2956 CFRunLoopAddSource (runloop
, source
, kCFRunLoopDefaultMode
);
2957 #ifdef SELECT_INVALIDATE_CFSOCKET
2967 err
= ReceiveNextEvent (0, NULL
, timeout_sec
, kEventLeaveInQueue
, NULL
);
2972 #ifdef SELECT_INVALIDATE_CFSOCKET
2973 CFSocketInvalidate (*s
);
2975 CFRunLoopRemoveSource (runloop
, *s
, kCFRunLoopDefaultMode
);
2990 FlushEventsMatchingListFromQueue (GetCurrentEventQueue (),
2991 GetEventTypeCount (specs
),
2993 EMACS_SET_SECS_USECS (select_timeout
, 0, 0);
2994 r
= select_and_poll_event (n
, rfds
, wfds
, efds
, &select_timeout
);
3001 #endif /* SELECT_USE_CFSOCKET */
3006 EMACS_TIME end_time
, now
, remaining_time
;
3007 SELECT_TYPE orfds
= *rfds
, owfds
, oefds
;
3015 remaining_time
= *timeout
;
3016 EMACS_GET_TIME (now
);
3017 EMACS_ADD_TIME (end_time
, now
, remaining_time
);
3022 EMACS_SET_SECS_USECS (select_timeout
, 0, SELECT_POLLING_PERIOD_USEC
);
3023 if (timeout
&& EMACS_TIME_LT (remaining_time
, select_timeout
))
3024 select_timeout
= remaining_time
;
3025 r
= select_and_poll_event (n
, rfds
, wfds
, efds
, &select_timeout
);
3037 EMACS_GET_TIME (now
);
3038 EMACS_SUB_TIME (remaining_time
, end_time
, now
);
3041 while (!timeout
|| EMACS_TIME_LT (now
, end_time
));
3052 /* Set up environment variables so that Emacs can correctly find its
3053 support files when packaged as an application bundle. Directories
3054 placed in /usr/local/share/emacs/<emacs-version>/, /usr/local/bin,
3055 and /usr/local/libexec/emacs/<emacs-version>/<system-configuration>
3056 by `make install' by default can instead be placed in
3057 .../Emacs.app/Contents/Resources/ and
3058 .../Emacs.app/Contents/MacOS/. Each of these environment variables
3059 is changed only if it is not already set. Presumably if the user
3060 sets an environment variable, he will want to use files in his path
3061 instead of ones in the application bundle. */
3063 init_mac_osx_environment ()
3067 CFStringRef cf_app_bundle_pathname
;
3068 int app_bundle_pathname_len
;
3069 char *app_bundle_pathname
;
3073 /* Fetch the pathname of the application bundle as a C string into
3074 app_bundle_pathname. */
3076 bundle
= CFBundleGetMainBundle ();
3080 bundleURL
= CFBundleCopyBundleURL (bundle
);
3084 cf_app_bundle_pathname
= CFURLCopyFileSystemPath (bundleURL
,
3085 kCFURLPOSIXPathStyle
);
3086 app_bundle_pathname_len
= CFStringGetLength (cf_app_bundle_pathname
);
3087 app_bundle_pathname
= (char *) alloca (app_bundle_pathname_len
+ 1);
3089 if (!CFStringGetCString (cf_app_bundle_pathname
,
3090 app_bundle_pathname
,
3091 app_bundle_pathname_len
+ 1,
3092 kCFStringEncodingISOLatin1
))
3094 CFRelease (cf_app_bundle_pathname
);
3098 CFRelease (cf_app_bundle_pathname
);
3100 /* P should have sufficient room for the pathname of the bundle plus
3101 the subpath in it leading to the respective directories. Q
3102 should have three times that much room because EMACSLOADPATH can
3103 have the value "<path to lisp dir>:<path to leim dir>:<path to
3105 p
= (char *) alloca (app_bundle_pathname_len
+ 50);
3106 q
= (char *) alloca (3 * app_bundle_pathname_len
+ 150);
3107 if (!getenv ("EMACSLOADPATH"))
3111 strcpy (p
, app_bundle_pathname
);
3112 strcat (p
, "/Contents/Resources/lisp");
3113 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
3116 strcpy (p
, app_bundle_pathname
);
3117 strcat (p
, "/Contents/Resources/leim");
3118 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
3125 strcpy (p
, app_bundle_pathname
);
3126 strcat (p
, "/Contents/Resources/site-lisp");
3127 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
3135 setenv ("EMACSLOADPATH", q
, 1);
3138 if (!getenv ("EMACSPATH"))
3142 strcpy (p
, app_bundle_pathname
);
3143 strcat (p
, "/Contents/MacOS/libexec");
3144 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
3147 strcpy (p
, app_bundle_pathname
);
3148 strcat (p
, "/Contents/MacOS/bin");
3149 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
3157 setenv ("EMACSPATH", q
, 1);
3160 if (!getenv ("EMACSDATA"))
3162 strcpy (p
, app_bundle_pathname
);
3163 strcat (p
, "/Contents/Resources/etc");
3164 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
3165 setenv ("EMACSDATA", p
, 1);
3168 if (!getenv ("EMACSDOC"))
3170 strcpy (p
, app_bundle_pathname
);
3171 strcat (p
, "/Contents/Resources/etc");
3172 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
3173 setenv ("EMACSDOC", p
, 1);
3176 if (!getenv ("INFOPATH"))
3178 strcpy (p
, app_bundle_pathname
);
3179 strcat (p
, "/Contents/Resources/info");
3180 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
3181 setenv ("INFOPATH", p
, 1);
3184 #endif /* MAC_OSX */
3189 QCLIPBOARD
= intern ("CLIPBOARD");
3190 staticpro (&QCLIPBOARD
);
3192 defsubr (&Smac_paste_function
);
3193 defsubr (&Smac_cut_function
);
3194 defsubr (&Sx_selection_exists_p
);
3195 defsubr (&Smac_clear_font_name_table
);
3197 defsubr (&Sdo_applescript
);
3198 defsubr (&Smac_file_name_to_posix
);
3199 defsubr (&Sposix_file_name_to_mac
);
3202 /* arch-tag: 29d30c1f-0c6b-4f88-8a6d-0558d7f9dbff
3203 (do not change this comment) */