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
);
849 select (n
, rfds
, wfds
, efds
, timeout
)
854 struct timeval
*timeout
;
856 #ifdef TARGET_API_MAC_CARBON
858 #else /* not TARGET_API_MAC_CARBON */
859 EMACS_TIME end_time
, now
;
862 /* Can only handle wait for keyboard input. */
863 if (n
> 1 || wfds
|| efds
)
866 EMACS_GET_TIME (end_time
);
867 EMACS_ADD_TIME (end_time
, end_time
, *timeout
);
871 /* Also return true if an event other than a keyDown has
872 occurred. This causes kbd_buffer_get_event in keyboard.c to
873 call read_avail_input which in turn calls XTread_socket to
874 poll for these events. Otherwise these never get processed
875 except but a very slow poll timer. */
876 if (FD_ISSET (0, rfds
) && EventAvail (everyEvent
, &e
))
879 /* Also check movement of the mouse. */
882 static Point old_mouse_pos
= {-1, -1};
884 GetMouse (&mouse_pos
);
885 if (!EqualPt (mouse_pos
, old_mouse_pos
))
887 old_mouse_pos
= mouse_pos
;
892 WaitNextEvent (0, &e
, 1UL, NULL
); /* Accept no event; wait 1
895 EMACS_GET_TIME (now
);
896 EMACS_SUB_TIME (now
, end_time
, now
);
898 while (!EMACS_TIME_NEG_P (now
));
901 #endif /* not TARGET_API_MAC_CARBON */
905 /* Called in sys_select to wait for an alarm signal to arrive. */
913 if (!target_ticks
) /* no alarm pending */
916 if ((tick
= TickCount ()) < target_ticks
)
917 WaitNextEvent (0, &e
, target_ticks
- tick
, NULL
); /* Accept no event;
918 just wait. by T.I. */
921 if (alarm_signal_func
)
922 (*alarm_signal_func
)(SIGALRM
);
931 long remaining
= target_ticks
? (TickCount () - target_ticks
) / 60 : 0;
933 target_ticks
= seconds
? TickCount () + 60 * seconds
: 0;
935 return (remaining
< 0) ? 0 : (unsigned int) remaining
;
941 extern __sigfun
signal (int signal
, __sigfun signal_func
);
943 sys_signal (int signal_num
, __sigfun signal_func
)
945 extern __signal_func_ptr
signal (int signal
, __signal_func_ptr signal_func
);
947 sys_signal (int signal_num
, __signal_func_ptr signal_func
)
948 #else /* not __MRC__ and not __MWERKS__ */
950 #endif /* not __MRC__ and not __MWERKS__ */
952 if (signal_num
!= SIGALRM
)
953 return signal (signal_num
, signal_func
);
957 __sigfun old_signal_func
;
959 __signal_func_ptr old_signal_func
;
963 old_signal_func
= alarm_signal_func
;
964 alarm_signal_func
= signal_func
;
965 return old_signal_func
;
970 /* gettimeofday should return the amount of time (in a timeval
971 structure) since midnight today. The toolbox function Microseconds
972 returns the number of microseconds (in a UnsignedWide value) since
973 the machine was booted. Also making this complicated is WideAdd,
974 WideSubtract, etc. take wide values. */
981 static wide wall_clock_at_epoch
, clicks_at_epoch
;
982 UnsignedWide uw_microseconds
;
984 time_t sys_time (time_t *);
986 /* If this function is called for the first time, record the number
987 of seconds since midnight and the number of microseconds since
988 boot at the time of this first call. */
993 systime
= sys_time (NULL
);
994 /* Store microseconds since midnight in wall_clock_at_epoch. */
995 WideMultiply (systime
, 1000000L, &wall_clock_at_epoch
);
996 Microseconds (&uw_microseconds
);
997 /* Store microseconds since boot in clicks_at_epoch. */
998 clicks_at_epoch
.hi
= uw_microseconds
.hi
;
999 clicks_at_epoch
.lo
= uw_microseconds
.lo
;
1002 /* Get time since boot */
1003 Microseconds (&uw_microseconds
);
1005 /* Convert to time since midnight*/
1006 w_microseconds
.hi
= uw_microseconds
.hi
;
1007 w_microseconds
.lo
= uw_microseconds
.lo
;
1008 WideSubtract (&w_microseconds
, &clicks_at_epoch
);
1009 WideAdd (&w_microseconds
, &wall_clock_at_epoch
);
1010 tp
->tv_sec
= WideDivide (&w_microseconds
, 1000000L, &tp
->tv_usec
);
1018 sleep (unsigned int seconds
)
1020 unsigned long time_up
;
1023 time_up
= TickCount () + seconds
* 60;
1024 while (TickCount () < time_up
)
1026 /* Accept no event; just wait. by T.I. */
1027 WaitNextEvent (0, &e
, 30, NULL
);
1032 #endif /* __MRC__ */
1035 /* The time functions adjust time values according to the difference
1036 between the Unix and CW epoches. */
1039 extern struct tm
*gmtime (const time_t *);
1041 sys_gmtime (const time_t *timer
)
1043 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
1045 return gmtime (&unix_time
);
1050 extern struct tm
*localtime (const time_t *);
1052 sys_localtime (const time_t *timer
)
1054 #if __MSL__ >= 0x6000
1055 time_t unix_time
= *timer
;
1057 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
1060 return localtime (&unix_time
);
1065 extern char *ctime (const time_t *);
1067 sys_ctime (const time_t *timer
)
1069 #if __MSL__ >= 0x6000
1070 time_t unix_time
= *timer
;
1072 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
1075 return ctime (&unix_time
);
1080 extern time_t time (time_t *);
1082 sys_time (time_t *timer
)
1084 #if __MSL__ >= 0x6000
1085 time_t mac_time
= time (NULL
);
1087 time_t mac_time
= time (NULL
) - CW_OR_MPW_UNIX_EPOCH_DIFF
;
1097 /* MPW strftime broken for "%p" format */
1102 sys_strftime (char * s
, size_t maxsize
, const char * format
,
1103 const struct tm
* timeptr
)
1105 if (strcmp (format
, "%p") == 0)
1109 if (timeptr
->tm_hour
< 12)
1121 return strftime (s
, maxsize
, format
, timeptr
);
1123 #endif /* __MRC__ */
1126 /* no subprocesses, empty wait */
1136 croak (char *badfunc
)
1138 printf ("%s not yet implemented\r\n", badfunc
);
1144 index (const char * str
, int chr
)
1146 return strchr (str
, chr
);
1151 mktemp (char *template)
1156 len
= strlen (template);
1158 while (k
>= 0 && template[k
] == 'X')
1161 k
++; /* make k index of first 'X' */
1165 /* Zero filled, number of digits equal to the number of X's. */
1166 sprintf (&template[k
], "%0*d", len
-k
, seqnum
++);
1175 /* Emulate getpwuid, getpwnam and others. */
1177 #define PASSWD_FIELD_SIZE 256
1179 static char my_passwd_name
[PASSWD_FIELD_SIZE
];
1180 static char my_passwd_dir
[MAXPATHLEN
+1];
1182 static struct passwd my_passwd
=
1188 static struct group my_group
=
1190 /* There are no groups on the mac, so we just return "root" as the
1196 /* Initialized by main () in macterm.c to pathname of emacs directory. */
1198 char emacs_passwd_dir
[MAXPATHLEN
+1];
1204 init_emacs_passwd_dir ()
1208 if (getwd (emacs_passwd_dir
) && getwd (my_passwd_dir
))
1210 /* Need pathname of first ancestor that begins with "emacs"
1211 since Mac emacs application is somewhere in the emacs-*
1213 int len
= strlen (emacs_passwd_dir
);
1215 /* j points to the "/" following the directory name being
1218 while (i
>= 0 && !found
)
1220 while (i
>= 0 && emacs_passwd_dir
[i
] != '/')
1222 if (emacs_passwd_dir
[i
] == '/' && i
+5 < len
)
1223 found
= (strncmp (&(emacs_passwd_dir
[i
+1]), "emacs", 5) == 0);
1225 emacs_passwd_dir
[j
+1] = '\0';
1236 /* Setting to "/" probably won't work but set it to something
1238 strcpy (emacs_passwd_dir
, "/");
1239 strcpy (my_passwd_dir
, "/");
1244 static struct passwd emacs_passwd
=
1250 static int my_passwd_inited
= 0;
1258 /* Note: my_passwd_dir initialized in int_emacs_passwd_dir to
1259 directory where Emacs was started. */
1261 owner_name
= (char **) GetResource ('STR ',-16096);
1265 BlockMove ((unsigned char *) *owner_name
,
1266 (unsigned char *) my_passwd_name
,
1268 HUnlock (owner_name
);
1269 p2cstr ((unsigned char *) my_passwd_name
);
1272 my_passwd_name
[0] = 0;
1277 getpwuid (uid_t uid
)
1279 if (!my_passwd_inited
)
1282 my_passwd_inited
= 1;
1290 getgrgid (gid_t gid
)
1297 getpwnam (const char *name
)
1299 if (strcmp (name
, "emacs") == 0)
1300 return &emacs_passwd
;
1302 if (!my_passwd_inited
)
1305 my_passwd_inited
= 1;
1312 /* The functions fork, kill, sigsetmask, sigblock, request_sigio,
1313 setpgrp, setpriority, and unrequest_sigio are defined to be empty
1334 error ("Can't spawn subshell");
1353 request_sigio (void)
1359 unrequest_sigio (void)
1374 pipe (int _fildes
[2])
1381 /* Hard and symbolic links. */
1384 symlink (const char *name1
, const char *name2
)
1392 link (const char *name1
, const char *name2
)
1398 #endif /* ! MAC_OSX */
1400 /* Determine the path name of the file specified by VREFNUM, DIRID,
1401 and NAME and place that in the buffer PATH of length
1404 path_from_vol_dir_name (char *path
, int man_path_len
, short vol_ref_num
,
1405 long dir_id
, ConstStr255Param name
)
1411 if (strlen (name
) > man_path_len
)
1414 memcpy (dir_name
, name
, name
[0]+1);
1415 memcpy (path
, name
, name
[0]+1);
1418 cipb
.dirInfo
.ioDrParID
= dir_id
;
1419 cipb
.dirInfo
.ioNamePtr
= dir_name
;
1423 cipb
.dirInfo
.ioVRefNum
= vol_ref_num
;
1424 cipb
.dirInfo
.ioFDirIndex
= -1;
1425 cipb
.dirInfo
.ioDrDirID
= cipb
.dirInfo
.ioDrParID
;
1426 /* go up to parent each time */
1428 err
= PBGetCatInfo (&cipb
, false);
1433 if (strlen (dir_name
) + strlen (path
) + 1 >= man_path_len
)
1436 strcat (dir_name
, ":");
1437 strcat (dir_name
, path
);
1438 /* attach to front since we're going up directory tree */
1439 strcpy (path
, dir_name
);
1441 while (cipb
.dirInfo
.ioDrDirID
!= fsRtDirID
);
1442 /* stop when we see the volume's root directory */
1444 return 1; /* success */
1450 readlink (const char *path
, char *buf
, int bufsiz
)
1452 char mac_sym_link_name
[MAXPATHLEN
+1];
1455 Boolean target_is_folder
, was_aliased
;
1456 Str255 directory_name
, mac_pathname
;
1459 if (posix_to_mac_pathname (path
, mac_sym_link_name
, MAXPATHLEN
+1) == 0)
1462 c2pstr (mac_sym_link_name
);
1463 err
= FSMakeFSSpec (0, 0, mac_sym_link_name
, &fsspec
);
1470 err
= ResolveAliasFile (&fsspec
, true, &target_is_folder
, &was_aliased
);
1471 if (err
!= noErr
|| !was_aliased
)
1477 if (path_from_vol_dir_name (mac_pathname
, 255, fsspec
.vRefNum
, fsspec
.parID
,
1484 if (mac_to_posix_pathname (mac_pathname
, buf
, bufsiz
) == 0)
1490 return strlen (buf
);
1494 /* Convert a path to one with aliases fully expanded. */
1497 find_true_pathname (const char *path
, char *buf
, int bufsiz
)
1499 char *q
, temp
[MAXPATHLEN
+1];
1503 if (bufsiz
<= 0 || path
== 0 || path
[0] == '\0')
1510 q
= strchr (p
+ 1, '/');
1512 q
= strchr (p
, '/');
1513 len
= 0; /* loop may not be entered, e.g., for "/" */
1518 strncat (temp
, p
, q
- p
);
1519 len
= readlink (temp
, buf
, bufsiz
);
1522 if (strlen (temp
) + 1 > bufsiz
)
1532 if (len
+ strlen (p
) + 1 >= bufsiz
)
1536 return len
+ strlen (p
);
1541 umask (mode_t numask
)
1543 static mode_t mask
= 022;
1544 mode_t oldmask
= mask
;
1551 chmod (const char *path
, mode_t mode
)
1553 /* say it always succeed for now */
1562 return fcntl (oldd
, F_DUPFD
, 0);
1564 /* current implementation of fcntl in fcntl.mac.c simply returns old
1566 return fcntl (oldd
, F_DUPFD
);
1573 /* This is from the original sysdep.c. Emulate BSD dup2. First close
1574 newd if it already exists. Then, attempt to dup oldd. If not
1575 successful, call dup2 recursively until we are, then close the
1576 unsuccessful ones. */
1579 dup2 (int oldd
, int newd
)
1590 ret
= dup2 (oldd
, newd
);
1596 /* let it fail for now */
1613 ioctl (int d
, int request
, void *argp
)
1623 if (fildes
>=0 && fildes
<= 2)
1656 #endif /* __MRC__ */
1660 #if __MSL__ < 0x6000
1668 #endif /* __MWERKS__ */
1670 #endif /* ! MAC_OSX */
1673 /* Return the path to the directory in which Emacs can create
1674 temporary files. The MacOS "temporary items" directory cannot be
1675 used because it removes the file written by a process when it
1676 exits. In that sense it's more like "/dev/null" than "/tmp" (but
1677 again not exactly). And of course Emacs needs to read back the
1678 files written by its subprocesses. So here we write the files to a
1679 directory "Emacs" in the Preferences Folder. This directory is
1680 created if it does not exist. */
1683 get_temp_dir_name ()
1685 static char *temp_dir_name
= NULL
;
1689 Str255 dir_name
, full_path
;
1691 char unix_dir_name
[MAXPATHLEN
+1];
1694 /* Cache directory name with pointer temp_dir_name.
1695 Look for it only the first time. */
1698 err
= FindFolder (kOnSystemDisk
, kPreferencesFolderType
, kCreateFolder
,
1699 &vol_ref_num
, &dir_id
);
1703 if (!path_from_vol_dir_name (full_path
, 255, vol_ref_num
, dir_id
, "\p"))
1706 if (strlen (full_path
) + 6 <= MAXPATHLEN
)
1707 strcat (full_path
, "Emacs:");
1711 if (!mac_to_posix_pathname (full_path
, unix_dir_name
, MAXPATHLEN
+1))
1714 dir
= opendir (unix_dir_name
); /* check whether temp directory exists */
1717 else if (mkdir (unix_dir_name
, 0700) != 0) /* create it if not */
1720 temp_dir_name
= (char *) malloc (strlen (unix_dir_name
) + 1);
1721 strcpy (temp_dir_name
, unix_dir_name
);
1724 return temp_dir_name
;
1729 /* Allocate and construct an array of pointers to strings from a list
1730 of strings stored in a 'STR#' resource. The returned pointer array
1731 is stored in the style of argv and environ: if the 'STR#' resource
1732 contains numString strings, a pointer array with numString+1
1733 elements is returned in which the last entry contains a null
1734 pointer. The pointer to the pointer array is passed by pointer in
1735 parameter t. The resource ID of the 'STR#' resource is passed in
1736 parameter StringListID.
1740 get_string_list (char ***t
, short string_list_id
)
1746 h
= GetResource ('STR#', string_list_id
);
1751 num_strings
= * (short *) p
;
1753 *t
= (char **) malloc (sizeof (char *) * (num_strings
+ 1));
1754 for (i
= 0; i
< num_strings
; i
++)
1756 short length
= *p
++;
1757 (*t
)[i
] = (char *) malloc (length
+ 1);
1758 strncpy ((*t
)[i
], p
, length
);
1759 (*t
)[i
][length
] = '\0';
1762 (*t
)[num_strings
] = 0;
1767 /* Return no string in case GetResource fails. Bug fixed by
1768 Ikegami Tsutomu. Caused MPW build to crash without sym -on
1769 option (no sym -on implies -opt local). */
1770 *t
= (char **) malloc (sizeof (char *));
1777 get_path_to_system_folder ()
1782 Str255 dir_name
, full_path
;
1784 static char system_folder_unix_name
[MAXPATHLEN
+1];
1787 err
= FindFolder (kOnSystemDisk
, kSystemFolderType
, kDontCreateFolder
,
1788 &vol_ref_num
, &dir_id
);
1792 if (!path_from_vol_dir_name (full_path
, 255, vol_ref_num
, dir_id
, "\p"))
1795 if (!mac_to_posix_pathname (full_path
, system_folder_unix_name
,
1799 return system_folder_unix_name
;
1805 #define ENVIRON_STRING_LIST_ID 128
1807 /* Get environment variable definitions from STR# resource. */
1814 get_string_list (&environ
, ENVIRON_STRING_LIST_ID
);
1820 /* Make HOME directory the one Emacs starts up in if not specified
1822 if (getenv ("HOME") == NULL
)
1824 environ
= (char **) realloc (environ
, sizeof (char *) * (i
+ 2));
1827 environ
[i
] = (char *) malloc (strlen (my_passwd_dir
) + 6);
1830 strcpy (environ
[i
], "HOME=");
1831 strcat (environ
[i
], my_passwd_dir
);
1838 /* Make HOME directory the one Emacs starts up in if not specified
1840 if (getenv ("MAIL") == NULL
)
1842 environ
= (char **) realloc (environ
, sizeof (char *) * (i
+ 2));
1845 char * path_to_system_folder
= get_path_to_system_folder ();
1846 environ
[i
] = (char *) malloc (strlen (path_to_system_folder
) + 22);
1849 strcpy (environ
[i
], "MAIL=");
1850 strcat (environ
[i
], path_to_system_folder
);
1851 strcat (environ
[i
], "Eudora Folder/In");
1859 /* Return the value of the environment variable NAME. */
1862 getenv (const char *name
)
1864 int length
= strlen(name
);
1867 for (e
= environ
; *e
!= 0; e
++)
1868 if (strncmp(*e
, name
, length
) == 0 && (*e
)[length
] == '=')
1869 return &(*e
)[length
+ 1];
1871 if (strcmp (name
, "TMPDIR") == 0)
1872 return get_temp_dir_name ();
1879 /* see Interfaces&Libraries:Interfaces:CIncludes:signal.h */
1880 char *sys_siglist
[] =
1882 "Zero is not a signal!!!",
1884 "Interactive user interrupt", /* 2 */ "?",
1885 "Floating point exception", /* 4 */ "?", "?", "?",
1886 "Illegal instruction", /* 8 */ "?", "?", "?", "?", "?", "?", "?",
1887 "Segment violation", /* 16 */ "?", "?", "?", "?", "?", "?", "?",
1888 "?", "?", "?", "?", "?", "?", "?", "?",
1892 char *sys_siglist
[] =
1894 "Zero is not a signal!!!",
1896 "Floating point exception",
1897 "Illegal instruction",
1898 "Interactive user interrupt",
1899 "Segment violation",
1902 #else /* not __MRC__ and not __MWERKS__ */
1904 #endif /* not __MRC__ and not __MWERKS__ */
1907 #include <utsname.h>
1910 uname (struct utsname
*name
)
1913 system_name
= GetString (-16413); /* IM - Resource Manager Reference */
1916 BlockMove (*system_name
, name
->nodename
, (*system_name
)[0]+1);
1917 p2cstr (name
->nodename
);
1925 #include <Processes.h>
1928 /* Event class of HLE sent to subprocess. */
1929 const OSType kEmacsSubprocessSend
= 'ESND';
1931 /* Event class of HLE sent back from subprocess. */
1932 const OSType kEmacsSubprocessReply
= 'ERPY';
1936 mystrchr (char *s
, char c
)
1938 while (*s
&& *s
!= c
)
1966 mystrcpy (char *to
, char *from
)
1978 /* Start a Mac subprocess. Arguments for it is passed in argv (null
1979 terminated). The process should run with the default directory
1980 "workdir", read input from "infn", and write output and error to
1981 "outfn" and "errfn", resp. The Process Manager call
1982 LaunchApplication is used to start the subprocess. We use high
1983 level events as the mechanism to pass arguments to the subprocess
1984 and to make Emacs wait for the subprocess to terminate and pass
1985 back a result code. The bulk of the code here packs the arguments
1986 into one message to be passed together with the high level event.
1987 Emacs also sometimes starts a subprocess using a shell to perform
1988 wildcard filename expansion. Since we don't really have a shell on
1989 the Mac, this case is detected and the starting of the shell is
1990 by-passed. We really need to add code here to do filename
1991 expansion to support such functionality. */
1994 run_mac_command (argv
, workdir
, infn
, outfn
, errfn
)
1995 unsigned char **argv
;
1996 const char *workdir
;
1997 const char *infn
, *outfn
, *errfn
;
1999 #ifdef TARGET_API_MAC_CARBON
2001 #else /* not TARGET_API_MAC_CARBON */
2002 char macappname
[MAXPATHLEN
+1], macworkdir
[MAXPATHLEN
+1];
2003 char macinfn
[MAXPATHLEN
+1], macoutfn
[MAXPATHLEN
+1], macerrfn
[MAXPATHLEN
+1];
2004 int paramlen
, argc
, newargc
, j
, retries
;
2005 char **newargv
, *param
, *p
;
2008 LaunchParamBlockRec lpbr
;
2009 EventRecord send_event
, reply_event
;
2010 RgnHandle cursor_region_handle
;
2012 unsigned long ref_con
, len
;
2014 if (posix_to_mac_pathname (workdir
, macworkdir
, MAXPATHLEN
+1) == 0)
2016 if (posix_to_mac_pathname (infn
, macinfn
, MAXPATHLEN
+1) == 0)
2018 if (posix_to_mac_pathname (outfn
, macoutfn
, MAXPATHLEN
+1) == 0)
2020 if (posix_to_mac_pathname (errfn
, macerrfn
, MAXPATHLEN
+1) == 0)
2023 paramlen
= strlen (macworkdir
) + strlen (macinfn
) + strlen (macoutfn
)
2024 + strlen (macerrfn
) + 4; /* count nulls at end of strings */
2033 /* If a subprocess is invoked with a shell, we receive 3 arguments
2034 of the form: "<path to emacs bins>/sh" "-c" "<path to emacs
2035 bins>/<command> <command args>" */
2036 j
= strlen (argv
[0]);
2037 if (j
>= 3 && strcmp (argv
[0]+j
-3, "/sh") == 0
2038 && argc
== 3 && strcmp (argv
[1], "-c") == 0)
2040 char *command
, *t
, tempmacpathname
[MAXPATHLEN
+1];
2042 /* The arguments for the command in argv[2] are separated by
2043 spaces. Count them and put the count in newargc. */
2044 command
= (char *) alloca (strlen (argv
[2])+2);
2045 strcpy (command
, argv
[2]);
2046 if (command
[strlen (command
) - 1] != ' ')
2047 strcat (command
, " ");
2051 t
= mystrchr (t
, ' ');
2055 t
= mystrchr (t
+1, ' ');
2058 newargv
= (char **) alloca (sizeof (char *) * newargc
);
2061 for (j
= 0; j
< newargc
; j
++)
2063 newargv
[j
] = (char *) alloca (strlen (t
) + 1);
2064 mystrcpy (newargv
[j
], t
);
2067 paramlen
+= strlen (newargv
[j
]) + 1;
2070 if (strncmp (newargv
[0], "~emacs/", 7) == 0)
2072 if (posix_to_mac_pathname (newargv
[0], tempmacpathname
, MAXPATHLEN
+1)
2077 { /* sometimes Emacs call "sh" without a path for the command */
2079 char *t
= (char *) alloca (strlen (newargv
[0]) + 7 + 1);
2080 strcpy (t
, "~emacs/");
2081 strcat (t
, newargv
[0]);
2084 openp (Vexec_path
, build_string (newargv
[0]), EXEC_SUFFIXES
, &path
,
2085 make_number (X_OK
));
2089 if (posix_to_mac_pathname (SDATA (path
), tempmacpathname
,
2093 strcpy (macappname
, tempmacpathname
);
2097 if (posix_to_mac_pathname (argv
[0], macappname
, MAXPATHLEN
+1) == 0)
2100 newargv
= (char **) alloca (sizeof (char *) * argc
);
2102 for (j
= 1; j
< argc
; j
++)
2104 if (strncmp (argv
[j
], "~emacs/", 7) == 0)
2106 char *t
= strchr (argv
[j
], ' ');
2109 char tempcmdname
[MAXPATHLEN
+1], tempmaccmdname
[MAXPATHLEN
+1];
2110 strncpy (tempcmdname
, argv
[j
], t
-argv
[j
]);
2111 tempcmdname
[t
-argv
[j
]] = '\0';
2112 if (posix_to_mac_pathname (tempcmdname
, tempmaccmdname
,
2115 newargv
[j
] = (char *) alloca (strlen (tempmaccmdname
)
2117 strcpy (newargv
[j
], tempmaccmdname
);
2118 strcat (newargv
[j
], t
);
2122 char tempmaccmdname
[MAXPATHLEN
+1];
2123 if (posix_to_mac_pathname (argv
[j
], tempmaccmdname
,
2126 newargv
[j
] = (char *) alloca (strlen (tempmaccmdname
)+1);
2127 strcpy (newargv
[j
], tempmaccmdname
);
2131 newargv
[j
] = argv
[j
];
2132 paramlen
+= strlen (newargv
[j
]) + 1;
2136 /* After expanding all the arguments, we now know the length of the
2137 parameter block to be sent to the subprocess as a message
2138 attached to the HLE. */
2139 param
= (char *) malloc (paramlen
+ 1);
2145 /* first byte of message contains number of arguments for command */
2146 strcpy (p
, macworkdir
);
2147 p
+= strlen (macworkdir
);
2149 /* null terminate strings sent so it's possible to use strcpy over there */
2150 strcpy (p
, macinfn
);
2151 p
+= strlen (macinfn
);
2153 strcpy (p
, macoutfn
);
2154 p
+= strlen (macoutfn
);
2156 strcpy (p
, macerrfn
);
2157 p
+= strlen (macerrfn
);
2159 for (j
= 1; j
< newargc
; j
++)
2161 strcpy (p
, newargv
[j
]);
2162 p
+= strlen (newargv
[j
]);
2166 c2pstr (macappname
);
2168 iErr
= FSMakeFSSpec (0, 0, macappname
, &spec
);
2176 lpbr
.launchBlockID
= extendedBlock
;
2177 lpbr
.launchEPBLength
= extendedBlockLen
;
2178 lpbr
.launchControlFlags
= launchContinue
+ launchNoFileFlags
;
2179 lpbr
.launchAppSpec
= &spec
;
2180 lpbr
.launchAppParameters
= NULL
;
2182 iErr
= LaunchApplication (&lpbr
); /* call the subprocess */
2189 send_event
.what
= kHighLevelEvent
;
2190 send_event
.message
= kEmacsSubprocessSend
;
2191 /* Event ID stored in "where" unused */
2194 /* OS may think current subprocess has terminated if previous one
2195 terminated recently. */
2198 iErr
= PostHighLevelEvent (&send_event
, &lpbr
.launchProcessSN
, 0, param
,
2199 paramlen
+ 1, receiverIDisPSN
);
2201 while (iErr
== sessClosedErr
&& retries
-- > 0);
2209 cursor_region_handle
= NewRgn ();
2211 /* Wait for the subprocess to finish, when it will send us a ERPY
2212 high level event. */
2214 if (WaitNextEvent (highLevelEventMask
, &reply_event
, 180,
2215 cursor_region_handle
)
2216 && reply_event
.message
== kEmacsSubprocessReply
)
2219 /* The return code is sent through the refCon */
2220 iErr
= AcceptHighLevelEvent (&targ
, &ref_con
, NULL
, &len
);
2223 DisposeHandle ((Handle
) cursor_region_handle
);
2228 DisposeHandle ((Handle
) cursor_region_handle
);
2232 #endif /* not TARGET_API_MAC_CARBON */
2237 opendir (const char *dirname
)
2239 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
2240 char mac_pathname
[MAXPATHLEN
+1], vol_name
[MAXPATHLEN
+1];
2244 int len
, vol_name_len
;
2246 if (find_true_pathname (dirname
, true_pathname
, MAXPATHLEN
+1) == -1)
2249 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
2251 fully_resolved_name
[len
] = '\0';
2253 strcpy (fully_resolved_name
, true_pathname
);
2255 dirp
= (DIR *) malloc (sizeof(DIR));
2259 /* Handle special case when dirname is "/": sets up for readir to
2260 get all mount volumes. */
2261 if (strcmp (fully_resolved_name
, "/") == 0)
2263 dirp
->getting_volumes
= 1; /* special all mounted volumes DIR struct */
2264 dirp
->current_index
= 1; /* index for first volume */
2268 /* Handle typical cases: not accessing all mounted volumes. */
2269 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
2272 /* Emacs calls opendir without the trailing '/', Mac needs trailing ':' */
2273 len
= strlen (mac_pathname
);
2274 if (mac_pathname
[len
- 1] != ':' && len
< MAXPATHLEN
)
2275 strcat (mac_pathname
, ":");
2277 /* Extract volume name */
2278 vol_name_len
= strchr (mac_pathname
, ':') - mac_pathname
;
2279 strncpy (vol_name
, mac_pathname
, vol_name_len
);
2280 vol_name
[vol_name_len
] = '\0';
2281 strcat (vol_name
, ":");
2283 c2pstr (mac_pathname
);
2284 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
2285 /* using full pathname so vRefNum and DirID ignored */
2286 cipb
.hFileInfo
.ioVRefNum
= 0;
2287 cipb
.hFileInfo
.ioDirID
= 0;
2288 cipb
.hFileInfo
.ioFDirIndex
= 0;
2289 /* set to 0 to get information about specific dir or file */
2291 errno
= PBGetCatInfo (&cipb
, false);
2298 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x10)) /* bit 4 = 1 for directories */
2299 return 0; /* not a directory */
2301 dirp
->dir_id
= cipb
.dirInfo
.ioDrDirID
; /* used later in readdir */
2302 dirp
->getting_volumes
= 0;
2303 dirp
->current_index
= 1; /* index for first file/directory */
2306 vpb
.ioNamePtr
= vol_name
;
2307 /* using full pathname so vRefNum and DirID ignored */
2309 vpb
.ioVolIndex
= -1;
2310 errno
= PBHGetVInfo ((union HParamBlockRec
*) &vpb
, false);
2317 dirp
->vol_ref_num
= vpb
.ioVRefNum
;
2334 HParamBlockRec hpblock
;
2336 static struct dirent s_dirent
;
2337 static Str255 s_name
;
2341 /* Handle the root directory containing the mounted volumes. Call
2342 PBHGetVInfo specifying an index to obtain the info for a volume.
2343 PBHGetVInfo returns an error when it receives an index beyond the
2344 last volume, at which time we should return a nil dirent struct
2346 if (dp
->getting_volumes
)
2348 hpblock
.volumeParam
.ioNamePtr
= s_name
;
2349 hpblock
.volumeParam
.ioVRefNum
= 0;
2350 hpblock
.volumeParam
.ioVolIndex
= dp
->current_index
;
2352 errno
= PBHGetVInfo (&hpblock
, false);
2360 strcat (s_name
, "/"); /* need "/" for stat to work correctly */
2362 dp
->current_index
++;
2364 s_dirent
.d_ino
= hpblock
.volumeParam
.ioVRefNum
;
2365 s_dirent
.d_name
= s_name
;
2371 cipb
.hFileInfo
.ioVRefNum
= dp
->vol_ref_num
;
2372 cipb
.hFileInfo
.ioNamePtr
= s_name
;
2373 /* location to receive filename returned */
2375 /* return only visible files */
2379 cipb
.hFileInfo
.ioDirID
= dp
->dir_id
;
2380 /* directory ID found by opendir */
2381 cipb
.hFileInfo
.ioFDirIndex
= dp
->current_index
;
2383 errno
= PBGetCatInfo (&cipb
, false);
2390 /* insist on a visible entry */
2391 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* directory? */
2392 done
= !(cipb
.dirInfo
.ioDrUsrWds
.frFlags
& fInvisible
);
2394 done
= !(cipb
.hFileInfo
.ioFlFndrInfo
.fdFlags
& fInvisible
);
2396 dp
->current_index
++;
2409 s_dirent
.d_ino
= cipb
.dirInfo
.ioDrDirID
;
2410 /* value unimportant: non-zero for valid file */
2411 s_dirent
.d_name
= s_name
;
2421 char mac_pathname
[MAXPATHLEN
+1];
2422 Str255 directory_name
;
2426 if (path_from_vol_dir_name (mac_pathname
, 255, 0, 0, "\p") == 0)
2429 if (mac_to_posix_pathname (mac_pathname
, path
, MAXPATHLEN
+1) == 0)
2435 #endif /* ! MAC_OSX */
2439 initialize_applescript ()
2444 /* if open fails, as_scripting_component is set to NULL. Its
2445 subsequent use in OSA calls will fail with badComponentInstance
2447 as_scripting_component
= OpenDefaultComponent (kOSAComponentType
,
2448 kAppleScriptSubtype
);
2450 null_desc
.descriptorType
= typeNull
;
2451 null_desc
.dataHandle
= 0;
2452 osaerror
= OSAMakeContext (as_scripting_component
, &null_desc
,
2453 kOSANullScript
, &as_script_context
);
2455 as_script_context
= kOSANullScript
;
2456 /* use default context if create fails */
2460 void terminate_applescript()
2462 OSADispose (as_scripting_component
, as_script_context
);
2463 CloseComponent (as_scripting_component
);
2467 /* Compile and execute the AppleScript SCRIPT and return the error
2468 status as function value. A zero is returned if compilation and
2469 execution is successful, in which case RESULT returns a pointer to
2470 a string containing the resulting script value. Otherwise, the Mac
2471 error code is returned and RESULT returns a pointer to an error
2472 string. In both cases the caller should deallocate the storage
2473 used by the string pointed to by RESULT if it is non-NULL. For
2474 documentation on the MacOS scripting architecture, see Inside
2475 Macintosh - Interapplication Communications: Scripting Components. */
2478 do_applescript (char *script
, char **result
)
2480 AEDesc script_desc
, result_desc
, error_desc
;
2487 if (!as_scripting_component
)
2488 initialize_applescript();
2490 error
= AECreateDesc (typeChar
, script
, strlen(script
), &script_desc
);
2494 osaerror
= OSADoScript (as_scripting_component
, &script_desc
, kOSANullScript
,
2495 typeChar
, kOSAModeNull
, &result_desc
);
2497 if (osaerror
== errOSAScriptError
)
2499 /* error executing AppleScript: retrieve error message */
2500 if (!OSAScriptError (as_scripting_component
, kOSAErrorMessage
, typeChar
,
2503 #if TARGET_API_MAC_CARBON
2504 length
= AEGetDescDataSize (&error_desc
);
2505 *result
= (char *) xmalloc (length
+ 1);
2508 AEGetDescData (&error_desc
, *result
, length
);
2509 *(*result
+ length
) = '\0';
2511 #else /* not TARGET_API_MAC_CARBON */
2512 HLock (error_desc
.dataHandle
);
2513 length
= GetHandleSize(error_desc
.dataHandle
);
2514 *result
= (char *) xmalloc (length
+ 1);
2517 memcpy (*result
, *(error_desc
.dataHandle
), length
);
2518 *(*result
+ length
) = '\0';
2520 HUnlock (error_desc
.dataHandle
);
2521 #endif /* not TARGET_API_MAC_CARBON */
2522 AEDisposeDesc (&error_desc
);
2525 else if (osaerror
== noErr
) /* success: retrieve resulting script value */
2527 #if TARGET_API_MAC_CARBON
2528 length
= AEGetDescDataSize (&result_desc
);
2529 *result
= (char *) xmalloc (length
+ 1);
2532 AEGetDescData (&result_desc
, *result
, length
);
2533 *(*result
+ length
) = '\0';
2535 #else /* not TARGET_API_MAC_CARBON */
2536 HLock (result_desc
.dataHandle
);
2537 length
= GetHandleSize(result_desc
.dataHandle
);
2538 *result
= (char *) xmalloc (length
+ 1);
2541 memcpy (*result
, *(result_desc
.dataHandle
), length
);
2542 *(*result
+ length
) = '\0';
2544 HUnlock (result_desc
.dataHandle
);
2545 #endif /* not TARGET_API_MAC_CARBON */
2546 AEDisposeDesc (&result_desc
);
2549 AEDisposeDesc (&script_desc
);
2555 DEFUN ("do-applescript", Fdo_applescript
, Sdo_applescript
, 1, 1, 0,
2556 doc
: /* Compile and execute AppleScript SCRIPT and retrieve and return the result.
2557 If compilation and execution are successful, the resulting script
2558 value is returned as a string. Otherwise the function aborts and
2559 displays the error message returned by the AppleScript scripting
2564 char *result
, *temp
;
2565 Lisp_Object lisp_result
;
2568 CHECK_STRING (script
);
2571 status
= do_applescript (SDATA (script
), &result
);
2576 error ("AppleScript error %d", status
);
2579 /* Unfortunately only OSADoScript in do_applescript knows how
2580 how large the resulting script value or error message is
2581 going to be and therefore as caller memory must be
2582 deallocated here. It is necessary to free the error
2583 message before calling error to avoid a memory leak. */
2584 temp
= (char *) alloca (strlen (result
) + 1);
2585 strcpy (temp
, result
);
2592 lisp_result
= build_string (result
);
2599 DEFUN ("mac-file-name-to-posix", Fmac_file_name_to_posix
,
2600 Smac_file_name_to_posix
, 1, 1, 0,
2601 doc
: /* Convert Macintosh filename to Posix form. */)
2603 Lisp_Object mac_filename
;
2605 char posix_filename
[MAXPATHLEN
+1];
2607 CHECK_STRING (mac_filename
);
2609 if (mac_to_posix_pathname (SDATA (mac_filename
), posix_filename
,
2611 return build_string (posix_filename
);
2617 DEFUN ("posix-file-name-to-mac", Fposix_file_name_to_mac
,
2618 Sposix_file_name_to_mac
, 1, 1, 0,
2619 doc
: /* Convert Posix filename to Mac form. */)
2621 Lisp_Object posix_filename
;
2623 char mac_filename
[MAXPATHLEN
+1];
2625 CHECK_STRING (posix_filename
);
2627 if (posix_to_mac_pathname (SDATA (posix_filename
), mac_filename
,
2629 return build_string (mac_filename
);
2635 /* set interprogram-paste-function to mac-paste-function in mac-win.el
2636 to enable Emacs to obtain the contents of the Mac clipboard. */
2637 DEFUN ("mac-paste-function", Fmac_paste_function
, Smac_paste_function
, 0, 0, 0,
2638 doc
: /* Return the contents of the Mac clipboard as a string. */)
2641 #if TARGET_API_MAC_CARBON
2644 ScrapFlavorFlags sff
;
2650 err
= GetCurrentScrap (&scrap
);
2652 err
= GetScrapFlavorFlags (scrap
, kScrapFlavorTypeText
, &sff
);
2654 err
= GetScrapFlavorSize (scrap
, kScrapFlavorTypeText
, &s
);
2655 if (err
== noErr
&& (data
= (char*) alloca (s
)))
2656 err
= GetScrapFlavorData (scrap
, kScrapFlavorTypeText
, &s
, data
);
2658 if (err
!= noErr
|| s
== 0)
2661 /* Emacs expects clipboard contents have Unix-style eol's */
2662 for (i
= 0; i
< s
; i
++)
2663 if (data
[i
] == '\r')
2666 return make_string (data
, s
);
2667 #else /* not TARGET_API_MAC_CARBON */
2670 long scrap_offset
, rc
, i
;
2672 my_handle
= NewHandle (0); /* allocate 0-length data area */
2674 rc
= GetScrap (my_handle
, 'TEXT', &scrap_offset
);
2680 /* Emacs expects clipboard contents have Unix-style eol's */
2681 for (i
= 0; i
< rc
; i
++)
2682 if ((*my_handle
)[i
] == '\r')
2683 (*my_handle
)[i
] = '\n';
2685 value
= make_string (*my_handle
, rc
);
2687 HUnlock (my_handle
);
2689 DisposeHandle (my_handle
);
2692 #endif /* not TARGET_API_MAC_CARBON */
2696 /* set interprogram-cut-function to mac-cut-function in mac-win.el
2697 to enable Emacs to write the top of the kill-ring to the Mac clipboard. */
2698 DEFUN ("mac-cut-function", Fmac_cut_function
, Smac_cut_function
, 1, 2, 0,
2699 doc
: /* Put the value of the string parameter to the Mac clipboard. */)
2701 Lisp_Object value
, push
;
2706 /* fixme: ignore the push flag for now */
2708 CHECK_STRING (value
);
2710 len
= SCHARS (value
);
2711 buf
= (char *) alloca (len
+1);
2712 bcopy (SDATA (value
), buf
, len
);
2715 /* convert to Mac-style eol's before sending to clipboard */
2716 for (i
= 0; i
< len
; i
++)
2720 #if TARGET_API_MAC_CARBON
2725 ClearCurrentScrap ();
2726 if (GetCurrentScrap (&scrap
) != noErr
)
2729 error ("cannot get current scrap");
2732 if (PutScrapFlavor (scrap
, kScrapFlavorTypeText
, kScrapFlavorMaskNone
, len
,
2736 error ("cannot put to scrap");
2740 #else /* not TARGET_API_MAC_CARBON */
2742 PutScrap (len
, 'TEXT', buf
);
2743 #endif /* not TARGET_API_MAC_CARBON */
2749 DEFUN ("x-selection-exists-p", Fx_selection_exists_p
, Sx_selection_exists_p
,
2751 doc
: /* Whether there is an owner for the given X Selection.
2752 The arg should be the name of the selection in question, typically one of
2753 the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.
2754 \(Those are literal upper-case symbol names, since that's what X expects.)
2755 For convenience, the symbol nil is the same as `PRIMARY',
2756 and t is the same as `SECONDARY'. */)
2758 Lisp_Object selection
;
2760 CHECK_SYMBOL (selection
);
2762 /* Return nil for PRIMARY and SECONDARY selections; for CLIPBOARD, check
2763 if the clipboard currently has valid text format contents. */
2765 if (EQ (selection
, QCLIPBOARD
))
2767 Lisp_Object val
= Qnil
;
2769 #if TARGET_API_MAC_CARBON
2771 ScrapFlavorFlags sff
;
2774 if (GetCurrentScrap (&scrap
) == noErr
)
2775 if (GetScrapFlavorFlags (scrap
, kScrapFlavorTypeText
, &sff
) == noErr
)
2778 #else /* not TARGET_API_MAC_CARBON */
2780 long rc
, scrap_offset
;
2782 my_handle
= NewHandle (0);
2784 rc
= GetScrap (my_handle
, 'TEXT', &scrap_offset
);
2788 DisposeHandle (my_handle
);
2789 #endif /* not TARGET_API_MAC_CARBON */
2799 extern int inhibit_window_system
;
2800 extern int noninteractive
;
2802 /* When Emacs is started from the Finder, SELECT always immediately
2803 returns as if input is present when file descriptor 0 is polled for
2804 input. Strangely, when Emacs is run as a GUI application from the
2805 command line, it blocks in the same situation. This `wrapper' of
2806 the system call SELECT corrects this discrepancy. */
2808 sys_select (n
, rfds
, wfds
, efds
, timeout
)
2813 struct timeval
*timeout
;
2816 EMACS_TIME end_time
, now
, remaining_time
;
2818 if (inhibit_window_system
|| noninteractive
2819 || rfds
== NULL
|| !FD_ISSET (0, rfds
))
2820 return select (n
, rfds
, wfds
, efds
, timeout
);
2822 if (wfds
== NULL
&& efds
== NULL
)
2826 for (i
= 1; i
< n
; i
++)
2827 if (FD_ISSET (i
, rfds
))
2831 EventTimeout timeout_sec
=
2833 ? (EMACS_SECS (*timeout
) * kEventDurationSecond
2834 + EMACS_USECS (*timeout
) * kEventDurationMicrosecond
)
2835 : kEventDurationForever
);
2838 err
= ReceiveNextEvent (0, NULL
, timeout_sec
,
2839 kEventLeaveInQueue
, NULL
);
2854 remaining_time
= *timeout
;
2855 EMACS_GET_TIME (now
);
2856 EMACS_ADD_TIME (end_time
, now
, remaining_time
);
2861 EMACS_TIME select_timeout
;
2862 SELECT_TYPE orfds
= *rfds
;
2865 EMACS_SET_SECS_USECS (select_timeout
, 0, 20000);
2867 if (timeout
&& EMACS_TIME_LT (remaining_time
, select_timeout
))
2868 select_timeout
= remaining_time
;
2870 r
= select (n
, &orfds
, wfds
, efds
, &select_timeout
);
2872 err
= ReceiveNextEvent (0, NULL
, kEventDurationNoWait
,
2873 kEventLeaveInQueue
, NULL
);
2885 else if (err
== noErr
)
2894 EMACS_GET_TIME (now
);
2895 EMACS_SUB_TIME (remaining_time
, end_time
, now
);
2898 while (!timeout
|| EMACS_TIME_LT (now
, end_time
));
2903 /* Set up environment variables so that Emacs can correctly find its
2904 support files when packaged as an application bundle. Directories
2905 placed in /usr/local/share/emacs/<emacs-version>/, /usr/local/bin,
2906 and /usr/local/libexec/emacs/<emacs-version>/<system-configuration>
2907 by `make install' by default can instead be placed in
2908 .../Emacs.app/Contents/Resources/ and
2909 .../Emacs.app/Contents/MacOS/. Each of these environment variables
2910 is changed only if it is not already set. Presumably if the user
2911 sets an environment variable, he will want to use files in his path
2912 instead of ones in the application bundle. */
2914 init_mac_osx_environment ()
2918 CFStringRef cf_app_bundle_pathname
;
2919 int app_bundle_pathname_len
;
2920 char *app_bundle_pathname
;
2924 /* Fetch the pathname of the application bundle as a C string into
2925 app_bundle_pathname. */
2927 bundle
= CFBundleGetMainBundle ();
2931 bundleURL
= CFBundleCopyBundleURL (bundle
);
2935 cf_app_bundle_pathname
= CFURLCopyFileSystemPath (bundleURL
,
2936 kCFURLPOSIXPathStyle
);
2937 app_bundle_pathname_len
= CFStringGetLength (cf_app_bundle_pathname
);
2938 app_bundle_pathname
= (char *) alloca (app_bundle_pathname_len
+ 1);
2940 if (!CFStringGetCString (cf_app_bundle_pathname
,
2941 app_bundle_pathname
,
2942 app_bundle_pathname_len
+ 1,
2943 kCFStringEncodingISOLatin1
))
2945 CFRelease (cf_app_bundle_pathname
);
2949 CFRelease (cf_app_bundle_pathname
);
2951 /* P should have sufficient room for the pathname of the bundle plus
2952 the subpath in it leading to the respective directories. Q
2953 should have three times that much room because EMACSLOADPATH can
2954 have the value "<path to lisp dir>:<path to leim dir>:<path to
2956 p
= (char *) alloca (app_bundle_pathname_len
+ 50);
2957 q
= (char *) alloca (3 * app_bundle_pathname_len
+ 150);
2958 if (!getenv ("EMACSLOADPATH"))
2962 strcpy (p
, app_bundle_pathname
);
2963 strcat (p
, "/Contents/Resources/lisp");
2964 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
2967 strcpy (p
, app_bundle_pathname
);
2968 strcat (p
, "/Contents/Resources/leim");
2969 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
2976 strcpy (p
, app_bundle_pathname
);
2977 strcat (p
, "/Contents/Resources/site-lisp");
2978 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
2986 setenv ("EMACSLOADPATH", q
, 1);
2989 if (!getenv ("EMACSPATH"))
2993 strcpy (p
, app_bundle_pathname
);
2994 strcat (p
, "/Contents/MacOS/libexec");
2995 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
2998 strcpy (p
, app_bundle_pathname
);
2999 strcat (p
, "/Contents/MacOS/bin");
3000 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
3008 setenv ("EMACSPATH", q
, 1);
3011 if (!getenv ("EMACSDATA"))
3013 strcpy (p
, app_bundle_pathname
);
3014 strcat (p
, "/Contents/Resources/etc");
3015 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
3016 setenv ("EMACSDATA", p
, 1);
3019 if (!getenv ("EMACSDOC"))
3021 strcpy (p
, app_bundle_pathname
);
3022 strcat (p
, "/Contents/Resources/etc");
3023 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
3024 setenv ("EMACSDOC", p
, 1);
3027 if (!getenv ("INFOPATH"))
3029 strcpy (p
, app_bundle_pathname
);
3030 strcat (p
, "/Contents/Resources/info");
3031 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
3032 setenv ("INFOPATH", p
, 1);
3035 #endif /* MAC_OSX */
3040 QCLIPBOARD
= intern ("CLIPBOARD");
3041 staticpro (&QCLIPBOARD
);
3043 defsubr (&Smac_paste_function
);
3044 defsubr (&Smac_cut_function
);
3045 defsubr (&Sx_selection_exists_p
);
3047 defsubr (&Sdo_applescript
);
3048 defsubr (&Smac_file_name_to_posix
);
3049 defsubr (&Sposix_file_name_to_mac
);
3052 /* arch-tag: 29d30c1f-0c6b-4f88-8a6d-0558d7f9dbff
3053 (do not change this comment) */