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). */
29 #include <sys/types.h>
33 #include <sys/param.h>
46 #include <Carbon/Carbon.h>
48 #define free unexec_free
50 #define malloc unexec_malloc
52 #define realloc unexec_realloc
54 #define init_process emacs_init_process
55 #else /* not MAC_OSX */
58 #include <TextUtils.h>
60 #include <Resources.h>
65 #include <AppleScript.h>
67 #endif /* not MAC_OSX */
71 #include "sysselect.h"
74 Lisp_Object QCLIPBOARD
;
76 /* An instance of the AppleScript component. */
77 static ComponentInstance as_scripting_component
;
78 /* The single script context used for all script executions. */
79 static OSAID as_script_context
;
82 /* When converting from Mac to Unix pathnames, /'s in folder names are
83 converted to :'s. This function, used in copying folder names,
84 performs a strncat and converts all character a to b in the copy of
85 the string s2 appended to the end of s1. */
88 string_cat_and_replace (char *s1
, const char *s2
, int n
, char a
, char b
)
96 for (i
= 0; i
< l2
; i
++)
105 /* Convert a Mac pathname to Posix form. A Mac full pathname is one
106 that does not begin with a ':' and contains at least one ':'. A Mac
107 full pathname causes a '/' to be prepended to the Posix pathname.
108 The algorithm for the rest of the pathname is as follows:
109 For each segment between two ':',
110 if it is non-null, copy as is and then add a '/' at the end,
111 otherwise, insert a "../" into the Posix pathname.
112 Returns 1 if successful; 0 if fails. */
115 mac_to_posix_pathname (const char *mfn
, char *ufn
, int ufnbuflen
)
117 const char *p
, *q
, *pe
;
124 p
= strchr (mfn
, ':');
125 if (p
!= 0 && p
!= mfn
) /* full pathname */
132 pe
= mfn
+ strlen (mfn
);
139 { /* two consecutive ':' */
140 if (strlen (ufn
) + 3 >= ufnbuflen
)
146 if (strlen (ufn
) + (q
- p
) + 1 >= ufnbuflen
)
148 string_cat_and_replace (ufn
, p
, q
- p
, '/', ':');
155 if (strlen (ufn
) + (pe
- p
) >= ufnbuflen
)
157 string_cat_and_replace (ufn
, p
, pe
- p
, '/', ':');
158 /* no separator for last one */
167 extern char *get_temp_dir_name ();
170 /* Convert a Posix pathname to Mac form. Approximately reverse of the
171 above in algorithm. */
174 posix_to_mac_pathname (const char *ufn
, char *mfn
, int mfnbuflen
)
176 const char *p
, *q
, *pe
;
177 char expanded_pathname
[MAXPATHLEN
+1];
186 /* Check for and handle volume names. Last comparison: strangely
187 somewhere "/.emacs" is passed. A temporary fix for now. */
188 if (*p
== '/' && strchr (p
+1, '/') == NULL
&& strcmp (p
, "/.emacs") != 0)
190 if (strlen (p
) + 1 > mfnbuflen
)
197 /* expand to emacs dir found by init_emacs_passwd_dir */
198 if (strncmp (p
, "~emacs/", 7) == 0)
200 struct passwd
*pw
= getpwnam ("emacs");
202 if (strlen (pw
->pw_dir
) + strlen (p
) > MAXPATHLEN
)
204 strcpy (expanded_pathname
, pw
->pw_dir
);
205 strcat (expanded_pathname
, p
);
206 p
= expanded_pathname
;
207 /* now p points to the pathname with emacs dir prefix */
209 else if (strncmp (p
, "/tmp/", 5) == 0)
211 char *t
= get_temp_dir_name ();
213 if (strlen (t
) + strlen (p
) > MAXPATHLEN
)
215 strcpy (expanded_pathname
, t
);
216 strcat (expanded_pathname
, p
);
217 p
= expanded_pathname
;
218 /* now p points to the pathname with emacs dir prefix */
220 else if (*p
!= '/') /* relative pathname */
232 if (q
- p
== 2 && *p
== '.' && *(p
+1) == '.')
234 if (strlen (mfn
) + 1 >= mfnbuflen
)
240 if (strlen (mfn
) + (q
- p
) + 1 >= mfnbuflen
)
242 string_cat_and_replace (mfn
, p
, q
- p
, ':', '/');
249 if (strlen (mfn
) + (pe
- p
) >= mfnbuflen
)
251 string_cat_and_replace (mfn
, p
, pe
- p
, ':', '/');
261 /* The following functions with "sys_" prefix are stubs to Unix
262 functions that have already been implemented by CW or MPW. The
263 calls to them in Emacs source course are #define'd to call the sys_
264 versions by the header files s-mac.h. In these stubs pathnames are
265 converted between their Unix and Mac forms. */
268 /* Unix epoch is Jan 1, 1970 while Mac epoch is Jan 1, 1904: 66 years
269 + 17 leap days. These are for adjusting time values returned by
270 MacOS Toolbox functions. */
272 #define MAC_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
276 /* CW Pro 5 epoch is Jan 1, 1900 (aaarghhhhh!); remember, 1900 is not
277 a leap year! This is for adjusting time_t values returned by MSL
279 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 70 + 17) * 24 * 60 * 60)
280 #else /* __MSL__ >= 0x6000 */
281 /* CW changes Pro 6 to follow Unix! */
282 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
283 #endif /* __MSL__ >= 0x6000 */
285 /* MPW library functions follow Unix (confused?). */
286 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
287 #else /* not __MRC__ */
289 #endif /* not __MRC__ */
292 /* Define our own stat function for both MrC and CW. The reason for
293 doing this: "stat" is both the name of a struct and function name:
294 can't use the same trick like that for sys_open, sys_close, etc. to
295 redirect Emacs's calls to our own version that converts Unix style
296 filenames to Mac style filename because all sorts of compilation
297 errors will be generated if stat is #define'd to be sys_stat. */
300 stat_noalias (const char *path
, struct stat
*buf
)
302 char mac_pathname
[MAXPATHLEN
+1];
305 if (posix_to_mac_pathname (path
, mac_pathname
, MAXPATHLEN
+1) == 0)
308 c2pstr (mac_pathname
);
309 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
310 cipb
.hFileInfo
.ioVRefNum
= 0;
311 cipb
.hFileInfo
.ioDirID
= 0;
312 cipb
.hFileInfo
.ioFDirIndex
= 0;
313 /* set to 0 to get information about specific dir or file */
315 errno
= PBGetCatInfo (&cipb
, false);
316 if (errno
== -43) /* -43: fnfErr defined in Errors.h */
321 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* bit 4 = 1 for directories */
323 buf
->st_mode
= S_IFDIR
| S_IREAD
| S_IEXEC
;
325 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x1))
326 buf
->st_mode
|= S_IWRITE
; /* bit 1 = 1 for locked files/directories */
327 buf
->st_ino
= cipb
.dirInfo
.ioDrDirID
;
328 buf
->st_dev
= cipb
.dirInfo
.ioVRefNum
;
329 buf
->st_size
= cipb
.dirInfo
.ioDrNmFls
;
330 /* size of dir = number of files and dirs */
333 = cipb
.dirInfo
.ioDrMdDat
- MAC_UNIX_EPOCH_DIFF
;
334 buf
->st_ctime
= cipb
.dirInfo
.ioDrCrDat
- MAC_UNIX_EPOCH_DIFF
;
338 buf
->st_mode
= S_IFREG
| S_IREAD
;
339 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x1))
340 buf
->st_mode
|= S_IWRITE
; /* bit 1 = 1 for locked files/directories */
341 if (cipb
.hFileInfo
.ioFlFndrInfo
.fdType
== 'APPL')
342 buf
->st_mode
|= S_IEXEC
;
343 buf
->st_ino
= cipb
.hFileInfo
.ioDirID
;
344 buf
->st_dev
= cipb
.hFileInfo
.ioVRefNum
;
345 buf
->st_size
= cipb
.hFileInfo
.ioFlLgLen
;
348 = cipb
.hFileInfo
.ioFlMdDat
- MAC_UNIX_EPOCH_DIFF
;
349 buf
->st_ctime
= cipb
.hFileInfo
.ioFlCrDat
- MAC_UNIX_EPOCH_DIFF
;
352 if (cipb
.hFileInfo
.ioFlFndrInfo
.fdFlags
& 0x8000)
354 /* identify alias files as symlinks */
355 buf
->st_mode
&= ~S_IFREG
;
356 buf
->st_mode
|= S_IFLNK
;
360 buf
->st_uid
= getuid ();
361 buf
->st_gid
= getgid ();
369 lstat (const char *path
, struct stat
*buf
)
372 char true_pathname
[MAXPATHLEN
+1];
374 /* Try looking for the file without resolving aliases first. */
375 if ((result
= stat_noalias (path
, buf
)) >= 0)
378 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
381 return stat_noalias (true_pathname
, buf
);
386 stat (const char *path
, struct stat
*sb
)
389 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
392 if ((result
= stat_noalias (path
, sb
)) >= 0 &&
393 ! (sb
->st_mode
& S_IFLNK
))
396 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
399 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
402 fully_resolved_name
[len
] = '\0';
403 /* in fact our readlink terminates strings */
404 return lstat (fully_resolved_name
, sb
);
407 return lstat (true_pathname
, sb
);
412 /* CW defines fstat in stat.mac.c while MPW does not provide this
413 function. Without the information of how to get from a file
414 descriptor in MPW StdCLib to a Mac OS file spec, it should be hard
415 to implement this function. Fortunately, there is only one place
416 where this function is called in our configuration: in fileio.c,
417 where only the st_dev and st_ino fields are used to determine
418 whether two fildes point to different i-nodes to prevent copying
419 a file onto itself equal. What we have here probably needs
423 fstat (int fildes
, struct stat
*buf
)
426 buf
->st_ino
= fildes
;
427 buf
->st_mode
= S_IFREG
; /* added by T.I. for the copy-file */
428 return 0; /* success */
434 mkdir (const char *dirname
, int mode
)
439 char true_pathname
[MAXPATHLEN
+1], mac_pathname
[MAXPATHLEN
+1];
441 if (find_true_pathname (dirname
, true_pathname
, MAXPATHLEN
+1) == -1)
444 if (posix_to_mac_pathname (true_pathname
, mac_pathname
, MAXPATHLEN
+1) == 0)
447 c2pstr (mac_pathname
);
448 hfpb
.ioNamePtr
= mac_pathname
;
449 hfpb
.ioVRefNum
= 0; /* ignored unless name is invalid */
450 hfpb
.ioDirID
= 0; /* parent is the root */
452 errno
= PBDirCreate ((HParmBlkPtr
) &hfpb
, false);
453 /* just return the Mac OSErr code for now */
454 return errno
== noErr
? 0 : -1;
459 sys_rmdir (const char *dirname
)
462 char mac_pathname
[MAXPATHLEN
+1];
464 if (posix_to_mac_pathname (dirname
, mac_pathname
, MAXPATHLEN
+1) == 0)
467 c2pstr (mac_pathname
);
468 hfpb
.ioNamePtr
= mac_pathname
;
469 hfpb
.ioVRefNum
= 0; /* ignored unless name is invalid */
470 hfpb
.ioDirID
= 0; /* parent is the root */
472 errno
= PBHDelete ((HParmBlkPtr
) &hfpb
, false);
473 return errno
== noErr
? 0 : -1;
478 /* No implementation yet. */
480 execvp (const char *path
, ...)
488 utime (const char *path
, const struct utimbuf
*times
)
490 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
492 char mac_pathname
[MAXPATHLEN
+1];
495 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
498 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
500 fully_resolved_name
[len
] = '\0';
502 strcpy (fully_resolved_name
, true_pathname
);
504 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
507 c2pstr (mac_pathname
);
508 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
509 cipb
.hFileInfo
.ioVRefNum
= 0;
510 cipb
.hFileInfo
.ioDirID
= 0;
511 cipb
.hFileInfo
.ioFDirIndex
= 0;
512 /* set to 0 to get information about specific dir or file */
514 errno
= PBGetCatInfo (&cipb
, false);
518 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* bit 4 = 1 for directories */
521 cipb
.dirInfo
.ioDrMdDat
= times
->modtime
+ MAC_UNIX_EPOCH_DIFF
;
523 GetDateTime (&cipb
.dirInfo
.ioDrMdDat
);
528 cipb
.hFileInfo
.ioFlMdDat
= times
->modtime
+ MAC_UNIX_EPOCH_DIFF
;
530 GetDateTime (&cipb
.hFileInfo
.ioFlMdDat
);
533 errno
= PBSetCatInfo (&cipb
, false);
534 return errno
== noErr
? 0 : -1;
548 /* Like stat, but test for access mode in hfpb.ioFlAttrib */
550 access (const char *path
, int mode
)
552 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
554 char mac_pathname
[MAXPATHLEN
+1];
557 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
560 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
562 fully_resolved_name
[len
] = '\0';
564 strcpy (fully_resolved_name
, true_pathname
);
566 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
569 c2pstr (mac_pathname
);
570 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
571 cipb
.hFileInfo
.ioVRefNum
= 0;
572 cipb
.hFileInfo
.ioDirID
= 0;
573 cipb
.hFileInfo
.ioFDirIndex
= 0;
574 /* set to 0 to get information about specific dir or file */
576 errno
= PBGetCatInfo (&cipb
, false);
580 if (mode
== F_OK
) /* got this far, file exists */
584 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* path refers to a directory */
588 if (cipb
.hFileInfo
.ioFlFndrInfo
.fdType
== 'APPL')
595 return (cipb
.hFileInfo
.ioFlAttrib
& 0x1) ? -1 : 0;
596 /* don't allow if lock bit is on */
602 #define DEV_NULL_FD 0x10000
606 sys_open (const char *path
, int oflag
)
608 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
610 char mac_pathname
[MAXPATHLEN
+1];
612 if (strcmp (path
, "/dev/null") == 0)
613 return DEV_NULL_FD
; /* some bogus fd to be ignored in write */
615 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
618 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
620 fully_resolved_name
[len
] = '\0';
622 strcpy (fully_resolved_name
, true_pathname
);
624 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
629 int res
= open (mac_pathname
, oflag
);
630 /* if (oflag == O_WRONLY || oflag == O_RDWR) */
632 fsetfileinfo (mac_pathname
, 'EMAx', 'TEXT');
634 #else /* not __MRC__ */
635 return open (mac_pathname
, oflag
);
636 #endif /* not __MRC__ */
643 sys_creat (const char *path
, mode_t mode
)
645 char true_pathname
[MAXPATHLEN
+1];
647 char mac_pathname
[MAXPATHLEN
+1];
649 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
652 if (!posix_to_mac_pathname (true_pathname
, mac_pathname
, MAXPATHLEN
+1))
657 int result
= creat (mac_pathname
);
658 fsetfileinfo (mac_pathname
, 'EMAx', 'TEXT');
660 #else /* not __MRC__ */
661 return creat (mac_pathname
, mode
);
662 #endif /* not __MRC__ */
669 sys_unlink (const char *path
)
671 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
673 char mac_pathname
[MAXPATHLEN
+1];
675 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
678 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
680 fully_resolved_name
[len
] = '\0';
682 strcpy (fully_resolved_name
, true_pathname
);
684 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
687 return unlink (mac_pathname
);
693 sys_read (int fildes
, char *buf
, int count
)
695 if (fildes
== 0) /* this should not be used for console input */
698 #if __MSL__ >= 0x6000
699 return _read (fildes
, buf
, count
);
701 return read (fildes
, buf
, count
);
708 sys_write (int fildes
, const char *buf
, int count
)
710 if (fildes
== DEV_NULL_FD
)
713 #if __MSL__ >= 0x6000
714 return _write (fildes
, buf
, count
);
716 return write (fildes
, buf
, count
);
723 sys_rename (const char * old_name
, const char * new_name
)
725 char true_old_pathname
[MAXPATHLEN
+1], true_new_pathname
[MAXPATHLEN
+1];
726 char fully_resolved_old_name
[MAXPATHLEN
+1];
728 char mac_old_name
[MAXPATHLEN
+1], mac_new_name
[MAXPATHLEN
+1];
730 if (find_true_pathname (old_name
, true_old_pathname
, MAXPATHLEN
+1) == -1)
733 len
= readlink (true_old_pathname
, fully_resolved_old_name
, MAXPATHLEN
);
735 fully_resolved_old_name
[len
] = '\0';
737 strcpy (fully_resolved_old_name
, true_old_pathname
);
739 if (find_true_pathname (new_name
, true_new_pathname
, MAXPATHLEN
+1) == -1)
742 if (strcmp (fully_resolved_old_name
, true_new_pathname
) == 0)
745 if (!posix_to_mac_pathname (fully_resolved_old_name
,
750 if (!posix_to_mac_pathname(true_new_pathname
, mac_new_name
, MAXPATHLEN
+1))
753 /* If a file with new_name already exists, rename deletes the old
754 file in Unix. CW version fails in these situation. So we add a
755 call to unlink here. */
756 (void) unlink (mac_new_name
);
758 return rename (mac_old_name
, mac_new_name
);
763 extern FILE *fopen (const char *name
, const char *mode
);
765 sys_fopen (const char *name
, const char *mode
)
767 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
769 char mac_pathname
[MAXPATHLEN
+1];
771 if (find_true_pathname (name
, true_pathname
, MAXPATHLEN
+1) == -1)
774 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
776 fully_resolved_name
[len
] = '\0';
778 strcpy (fully_resolved_name
, true_pathname
);
780 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
785 if (mode
[0] == 'w' || mode
[0] == 'a')
786 fsetfileinfo (mac_pathname
, 'EMAx', 'TEXT');
787 #endif /* not __MRC__ */
788 return fopen (mac_pathname
, mode
);
795 long target_ticks
= 0;
798 __sigfun alarm_signal_func
= (__sigfun
) 0;
800 __signal_func_ptr alarm_signal_func
= (__signal_func_ptr
) 0;
801 #else /* not __MRC__ and not __MWERKS__ */
803 #endif /* not __MRC__ and not __MWERKS__ */
806 /* These functions simulate SIG_ALRM. The stub for function signal
807 stores the signal handler function in alarm_signal_func if a
808 SIG_ALRM is encountered. check_alarm is called in XTread_socket,
809 which emacs calls periodically. A pending alarm is represented by
810 a non-zero target_ticks value. check_alarm calls the handler
811 function pointed to by alarm_signal_func if one has been set up and
812 an alarm is pending. */
817 if (target_ticks
&& TickCount () > target_ticks
)
820 if (alarm_signal_func
)
821 (*alarm_signal_func
)(SIGALRM
);
827 select (n
, rfds
, wfds
, efds
, timeout
)
832 struct timeval
*timeout
;
834 #ifdef TARGET_API_MAC_CARBON
836 #else /* not TARGET_API_MAC_CARBON */
837 EMACS_TIME end_time
, now
;
840 /* Can only handle wait for keyboard input. */
841 if (n
> 1 || wfds
|| efds
)
844 EMACS_GET_TIME (end_time
);
845 EMACS_ADD_TIME (end_time
, end_time
, *timeout
);
849 /* Also return true if an event other than a keyDown has
850 occurred. This causes kbd_buffer_get_event in keyboard.c to
851 call read_avail_input which in turn calls XTread_socket to
852 poll for these events. Otherwise these never get processed
853 except but a very slow poll timer. */
854 if (FD_ISSET (0, rfds
) && EventAvail (everyEvent
, &e
))
857 /* Also check movement of the mouse. */
860 static Point old_mouse_pos
= {-1, -1};
862 GetMouse (&mouse_pos
);
863 if (!EqualPt (mouse_pos
, old_mouse_pos
))
865 old_mouse_pos
= mouse_pos
;
870 WaitNextEvent (0, &e
, 1UL, NULL
); /* Accept no event; wait 1
873 EMACS_GET_TIME (now
);
874 EMACS_SUB_TIME (now
, end_time
, now
);
876 while (!EMACS_TIME_NEG_P (now
));
879 #endif /* not TARGET_API_MAC_CARBON */
883 /* Called in sys_select to wait for an alarm signal to arrive. */
891 if (!target_ticks
) /* no alarm pending */
894 if ((tick
= TickCount ()) < target_ticks
)
895 WaitNextEvent (0, &e
, target_ticks
- tick
, NULL
); /* Accept no event;
896 just wait. by T.I. */
899 if (alarm_signal_func
)
900 (*alarm_signal_func
)(SIGALRM
);
909 long remaining
= target_ticks
? (TickCount () - target_ticks
) / 60 : 0;
911 target_ticks
= seconds
? TickCount () + 60 * seconds
: 0;
913 return (remaining
< 0) ? 0 : (unsigned int) remaining
;
919 extern __sigfun
signal (int signal
, __sigfun signal_func
);
921 sys_signal (int signal_num
, __sigfun signal_func
)
923 extern __signal_func_ptr
signal (int signal
, __signal_func_ptr signal_func
);
925 sys_signal (int signal_num
, __signal_func_ptr signal_func
)
926 #else /* not __MRC__ and not __MWERKS__ */
928 #endif /* not __MRC__ and not __MWERKS__ */
930 if (signal_num
!= SIGALRM
)
931 return signal (signal_num
, signal_func
);
935 __sigfun old_signal_func
;
937 __signal_func_ptr old_signal_func
;
941 old_signal_func
= alarm_signal_func
;
942 alarm_signal_func
= signal_func
;
943 return old_signal_func
;
948 /* gettimeofday should return the amount of time (in a timeval
949 structure) since midnight today. The toolbox function Microseconds
950 returns the number of microseconds (in a UnsignedWide value) since
951 the machine was booted. Also making this complicated is WideAdd,
952 WideSubtract, etc. take wide values. */
959 static wide wall_clock_at_epoch
, clicks_at_epoch
;
960 UnsignedWide uw_microseconds
;
962 time_t sys_time (time_t *);
964 /* If this function is called for the first time, record the number
965 of seconds since midnight and the number of microseconds since
966 boot at the time of this first call. */
971 systime
= sys_time (NULL
);
972 /* Store microseconds since midnight in wall_clock_at_epoch. */
973 WideMultiply (systime
, 1000000L, &wall_clock_at_epoch
);
974 Microseconds (&uw_microseconds
);
975 /* Store microseconds since boot in clicks_at_epoch. */
976 clicks_at_epoch
.hi
= uw_microseconds
.hi
;
977 clicks_at_epoch
.lo
= uw_microseconds
.lo
;
980 /* Get time since boot */
981 Microseconds (&uw_microseconds
);
983 /* Convert to time since midnight*/
984 w_microseconds
.hi
= uw_microseconds
.hi
;
985 w_microseconds
.lo
= uw_microseconds
.lo
;
986 WideSubtract (&w_microseconds
, &clicks_at_epoch
);
987 WideAdd (&w_microseconds
, &wall_clock_at_epoch
);
988 tp
->tv_sec
= WideDivide (&w_microseconds
, 1000000L, &tp
->tv_usec
);
996 sleep (unsigned int seconds
)
998 unsigned long time_up
;
1001 time_up
= TickCount () + seconds
* 60;
1002 while (TickCount () < time_up
)
1004 /* Accept no event; just wait. by T.I. */
1005 WaitNextEvent (0, &e
, 30, NULL
);
1010 #endif /* __MRC__ */
1013 /* The time functions adjust time values according to the difference
1014 between the Unix and CW epoches. */
1017 extern struct tm
*gmtime (const time_t *);
1019 sys_gmtime (const time_t *timer
)
1021 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
1023 return gmtime (&unix_time
);
1028 extern struct tm
*localtime (const time_t *);
1030 sys_localtime (const time_t *timer
)
1032 #if __MSL__ >= 0x6000
1033 time_t unix_time
= *timer
;
1035 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
1038 return localtime (&unix_time
);
1043 extern char *ctime (const time_t *);
1045 sys_ctime (const time_t *timer
)
1047 #if __MSL__ >= 0x6000
1048 time_t unix_time
= *timer
;
1050 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
1053 return ctime (&unix_time
);
1058 extern time_t time (time_t *);
1060 sys_time (time_t *timer
)
1062 #if __MSL__ >= 0x6000
1063 time_t mac_time
= time (NULL
);
1065 time_t mac_time
= time (NULL
) - CW_OR_MPW_UNIX_EPOCH_DIFF
;
1075 /* MPW strftime broken for "%p" format */
1080 sys_strftime (char * s
, size_t maxsize
, const char * format
,
1081 const struct tm
* timeptr
)
1083 if (strcmp (format
, "%p") == 0)
1087 if (timeptr
->tm_hour
< 12)
1099 return strftime (s
, maxsize
, format
, timeptr
);
1101 #endif /* __MRC__ */
1104 /* no subprocesses, empty wait */
1114 croak (char *badfunc
)
1116 printf ("%s not yet implemented\r\n", badfunc
);
1122 index (const char * str
, int chr
)
1124 return strchr (str
, chr
);
1129 mktemp (char *template)
1134 len
= strlen (template);
1136 while (k
>= 0 && template[k
] == 'X')
1139 k
++; /* make k index of first 'X' */
1143 /* Zero filled, number of digits equal to the number of X's. */
1144 sprintf (&template[k
], "%0*d", len
-k
, seqnum
++);
1153 /* Emulate getpwuid, getpwnam and others. */
1155 #define PASSWD_FIELD_SIZE 256
1157 static char my_passwd_name
[PASSWD_FIELD_SIZE
];
1158 static char my_passwd_dir
[MAXPATHLEN
+1];
1160 static struct passwd my_passwd
=
1167 /* Initialized by main () in macterm.c to pathname of emacs directory. */
1169 char emacs_passwd_dir
[MAXPATHLEN
+1];
1175 init_emacs_passwd_dir ()
1179 if (getwd (emacs_passwd_dir
) && getwd (my_passwd_dir
))
1181 /* Need pathname of first ancestor that begins with "emacs"
1182 since Mac emacs application is somewhere in the emacs-*
1184 int len
= strlen (emacs_passwd_dir
);
1186 /* j points to the "/" following the directory name being
1189 while (i
>= 0 && !found
)
1191 while (i
>= 0 && emacs_passwd_dir
[i
] != '/')
1193 if (emacs_passwd_dir
[i
] == '/' && i
+5 < len
)
1194 found
= (strncmp (&(emacs_passwd_dir
[i
+1]), "emacs", 5) == 0);
1196 emacs_passwd_dir
[j
+1] = '\0';
1207 /* Setting to "/" probably won't work but set it to something
1209 strcpy (emacs_passwd_dir
, "/");
1210 strcpy (my_passwd_dir
, "/");
1215 static struct passwd emacs_passwd
=
1221 static int my_passwd_inited
= 0;
1229 /* Note: my_passwd_dir initialized in int_emacs_passwd_dir to
1230 directory where Emacs was started. */
1232 owner_name
= (char **) GetResource ('STR ',-16096);
1236 BlockMove ((unsigned char *) *owner_name
,
1237 (unsigned char *) my_passwd_name
,
1239 HUnlock (owner_name
);
1240 p2cstr ((unsigned char *) my_passwd_name
);
1243 my_passwd_name
[0] = 0;
1248 getpwuid (uid_t uid
)
1250 if (!my_passwd_inited
)
1253 my_passwd_inited
= 1;
1261 getpwnam (const char *name
)
1263 if (strcmp (name
, "emacs") == 0)
1264 return &emacs_passwd
;
1266 if (!my_passwd_inited
)
1269 my_passwd_inited
= 1;
1276 /* The functions fork, kill, sigsetmask, sigblock, request_sigio,
1277 setpgrp, setpriority, and unrequest_sigio are defined to be empty
1298 error ("Can't spawn subshell");
1317 request_sigio (void)
1323 unrequest_sigio (void)
1338 pipe (int _fildes
[2])
1345 /* Hard and symbolic links. */
1348 symlink (const char *name1
, const char *name2
)
1356 link (const char *name1
, const char *name2
)
1362 #endif /* ! MAC_OSX */
1364 /* Determine the path name of the file specified by VREFNUM, DIRID,
1365 and NAME and place that in the buffer PATH of length
1368 path_from_vol_dir_name (char *path
, int man_path_len
, short vol_ref_num
,
1369 long dir_id
, ConstStr255Param name
)
1375 if (strlen (name
) > man_path_len
)
1378 memcpy (dir_name
, name
, name
[0]+1);
1379 memcpy (path
, name
, name
[0]+1);
1382 cipb
.dirInfo
.ioDrParID
= dir_id
;
1383 cipb
.dirInfo
.ioNamePtr
= dir_name
;
1387 cipb
.dirInfo
.ioVRefNum
= vol_ref_num
;
1388 cipb
.dirInfo
.ioFDirIndex
= -1;
1389 cipb
.dirInfo
.ioDrDirID
= cipb
.dirInfo
.ioDrParID
;
1390 /* go up to parent each time */
1392 err
= PBGetCatInfo (&cipb
, false);
1397 if (strlen (dir_name
) + strlen (path
) + 1 >= man_path_len
)
1400 strcat (dir_name
, ":");
1401 strcat (dir_name
, path
);
1402 /* attach to front since we're going up directory tree */
1403 strcpy (path
, dir_name
);
1405 while (cipb
.dirInfo
.ioDrDirID
!= fsRtDirID
);
1406 /* stop when we see the volume's root directory */
1408 return 1; /* success */
1414 readlink (const char *path
, char *buf
, int bufsiz
)
1416 char mac_sym_link_name
[MAXPATHLEN
+1];
1419 Boolean target_is_folder
, was_aliased
;
1420 Str255 directory_name
, mac_pathname
;
1423 if (posix_to_mac_pathname (path
, mac_sym_link_name
, MAXPATHLEN
+1) == 0)
1426 c2pstr (mac_sym_link_name
);
1427 err
= FSMakeFSSpec (0, 0, mac_sym_link_name
, &fsspec
);
1434 err
= ResolveAliasFile (&fsspec
, true, &target_is_folder
, &was_aliased
);
1435 if (err
!= noErr
|| !was_aliased
)
1441 if (path_from_vol_dir_name (mac_pathname
, 255, fsspec
.vRefNum
, fsspec
.parID
,
1448 if (mac_to_posix_pathname (mac_pathname
, buf
, bufsiz
) == 0)
1454 return strlen (buf
);
1458 /* Convert a path to one with aliases fully expanded. */
1461 find_true_pathname (const char *path
, char *buf
, int bufsiz
)
1463 char *q
, temp
[MAXPATHLEN
+1];
1467 if (bufsiz
<= 0 || path
== 0 || path
[0] == '\0')
1474 q
= strchr (p
+ 1, '/');
1476 q
= strchr (p
, '/');
1477 len
= 0; /* loop may not be entered, e.g., for "/" */
1482 strncat (temp
, p
, q
- p
);
1483 len
= readlink (temp
, buf
, bufsiz
);
1486 if (strlen (temp
) + 1 > bufsiz
)
1496 if (len
+ strlen (p
) + 1 >= bufsiz
)
1500 return len
+ strlen (p
);
1505 umask (mode_t numask
)
1507 static mode_t mask
= 022;
1508 mode_t oldmask
= mask
;
1515 chmod (const char *path
, mode_t mode
)
1517 /* say it always succeed for now */
1526 return fcntl (oldd
, F_DUPFD
, 0);
1528 /* current implementation of fcntl in fcntl.mac.c simply returns old
1530 return fcntl (oldd
, F_DUPFD
);
1537 /* This is from the original sysdep.c. Emulate BSD dup2. First close
1538 newd if it already exists. Then, attempt to dup oldd. If not
1539 successful, call dup2 recursively until we are, then close the
1540 unsuccessful ones. */
1543 dup2 (int oldd
, int newd
)
1554 ret
= dup2 (oldd
, newd
);
1560 /* let it fail for now */
1577 ioctl (int d
, int request
, void *argp
)
1587 if (fildes
>=0 && fildes
<= 2)
1620 #endif /* __MRC__ */
1624 #if __MSL__ < 0x6000
1632 #endif /* __MWERKS__ */
1634 #endif /* ! MAC_OSX */
1637 /* Return the path to the directory in which Emacs can create
1638 temporary files. The MacOS "temporary items" directory cannot be
1639 used because it removes the file written by a process when it
1640 exits. In that sense it's more like "/dev/null" than "/tmp" (but
1641 again not exactly). And of course Emacs needs to read back the
1642 files written by its subprocesses. So here we write the files to a
1643 directory "Emacs" in the Preferences Folder. This directory is
1644 created if it does not exist. */
1647 get_temp_dir_name ()
1649 static char *temp_dir_name
= NULL
;
1653 Str255 dir_name
, full_path
;
1655 char unix_dir_name
[MAXPATHLEN
+1];
1658 /* Cache directory name with pointer temp_dir_name.
1659 Look for it only the first time. */
1662 err
= FindFolder (kOnSystemDisk
, kPreferencesFolderType
, kCreateFolder
,
1663 &vol_ref_num
, &dir_id
);
1667 if (!path_from_vol_dir_name (full_path
, 255, vol_ref_num
, dir_id
, "\p"))
1670 if (strlen (full_path
) + 6 <= MAXPATHLEN
)
1671 strcat (full_path
, "Emacs:");
1675 if (!mac_to_posix_pathname (full_path
, unix_dir_name
, MAXPATHLEN
+1))
1678 dir
= opendir (unix_dir_name
); /* check whether temp directory exists */
1681 else if (mkdir (unix_dir_name
, 0700) != 0) /* create it if not */
1684 temp_dir_name
= (char *) malloc (strlen (unix_dir_name
) + 1);
1685 strcpy (temp_dir_name
, unix_dir_name
);
1688 return temp_dir_name
;
1693 /* Allocate and construct an array of pointers to strings from a list
1694 of strings stored in a 'STR#' resource. The returned pointer array
1695 is stored in the style of argv and environ: if the 'STR#' resource
1696 contains numString strings, a pointer array with numString+1
1697 elements is returned in which the last entry contains a null
1698 pointer. The pointer to the pointer array is passed by pointer in
1699 parameter t. The resource ID of the 'STR#' resource is passed in
1700 parameter StringListID.
1704 get_string_list (char ***t
, short string_list_id
)
1710 h
= GetResource ('STR#', string_list_id
);
1715 num_strings
= * (short *) p
;
1717 *t
= (char **) malloc (sizeof (char *) * (num_strings
+ 1));
1718 for (i
= 0; i
< num_strings
; i
++)
1720 short length
= *p
++;
1721 (*t
)[i
] = (char *) malloc (length
+ 1);
1722 strncpy ((*t
)[i
], p
, length
);
1723 (*t
)[i
][length
] = '\0';
1726 (*t
)[num_strings
] = 0;
1731 /* Return no string in case GetResource fails. Bug fixed by
1732 Ikegami Tsutomu. Caused MPW build to crash without sym -on
1733 option (no sym -on implies -opt local). */
1734 *t
= (char **) malloc (sizeof (char *));
1741 get_path_to_system_folder ()
1746 Str255 dir_name
, full_path
;
1748 static char system_folder_unix_name
[MAXPATHLEN
+1];
1751 err
= FindFolder (kOnSystemDisk
, kSystemFolderType
, kDontCreateFolder
,
1752 &vol_ref_num
, &dir_id
);
1756 if (!path_from_vol_dir_name (full_path
, 255, vol_ref_num
, dir_id
, "\p"))
1759 if (!mac_to_posix_pathname (full_path
, system_folder_unix_name
,
1763 return system_folder_unix_name
;
1769 #define ENVIRON_STRING_LIST_ID 128
1771 /* Get environment variable definitions from STR# resource. */
1778 get_string_list (&environ
, ENVIRON_STRING_LIST_ID
);
1784 /* Make HOME directory the one Emacs starts up in if not specified
1786 if (getenv ("HOME") == NULL
)
1788 environ
= (char **) realloc (environ
, sizeof (char *) * (i
+ 2));
1791 environ
[i
] = (char *) malloc (strlen (my_passwd_dir
) + 6);
1794 strcpy (environ
[i
], "HOME=");
1795 strcat (environ
[i
], my_passwd_dir
);
1802 /* Make HOME directory the one Emacs starts up in if not specified
1804 if (getenv ("MAIL") == NULL
)
1806 environ
= (char **) realloc (environ
, sizeof (char *) * (i
+ 2));
1809 char * path_to_system_folder
= get_path_to_system_folder ();
1810 environ
[i
] = (char *) malloc (strlen (path_to_system_folder
) + 22);
1813 strcpy (environ
[i
], "MAIL=");
1814 strcat (environ
[i
], path_to_system_folder
);
1815 strcat (environ
[i
], "Eudora Folder/In");
1823 /* Return the value of the environment variable NAME. */
1826 getenv (const char *name
)
1828 int length
= strlen(name
);
1831 for (e
= environ
; *e
!= 0; e
++)
1832 if (strncmp(*e
, name
, length
) == 0 && (*e
)[length
] == '=')
1833 return &(*e
)[length
+ 1];
1835 if (strcmp (name
, "TMPDIR") == 0)
1836 return get_temp_dir_name ();
1843 /* see Interfaces&Libraries:Interfaces:CIncludes:signal.h */
1844 char *sys_siglist
[] =
1846 "Zero is not a signal!!!",
1848 "Interactive user interrupt", /* 2 */ "?",
1849 "Floating point exception", /* 4 */ "?", "?", "?",
1850 "Illegal instruction", /* 8 */ "?", "?", "?", "?", "?", "?", "?",
1851 "Segment violation", /* 16 */ "?", "?", "?", "?", "?", "?", "?",
1852 "?", "?", "?", "?", "?", "?", "?", "?",
1856 char *sys_siglist
[] =
1858 "Zero is not a signal!!!",
1860 "Floating point exception",
1861 "Illegal instruction",
1862 "Interactive user interrupt",
1863 "Segment violation",
1866 #else /* not __MRC__ and not __MWERKS__ */
1868 #endif /* not __MRC__ and not __MWERKS__ */
1871 #include <utsname.h>
1874 uname (struct utsname
*name
)
1877 system_name
= GetString (-16413); /* IM - Resource Manager Reference */
1880 BlockMove (*system_name
, name
->nodename
, (*system_name
)[0]+1);
1881 p2cstr (name
->nodename
);
1889 #include <Processes.h>
1892 /* Event class of HLE sent to subprocess. */
1893 const OSType kEmacsSubprocessSend
= 'ESND';
1895 /* Event class of HLE sent back from subprocess. */
1896 const OSType kEmacsSubprocessReply
= 'ERPY';
1900 mystrchr (char *s
, char c
)
1902 while (*s
&& *s
!= c
)
1930 mystrcpy (char *to
, char *from
)
1942 /* Start a Mac subprocess. Arguments for it is passed in argv (null
1943 terminated). The process should run with the default directory
1944 "workdir", read input from "infn", and write output and error to
1945 "outfn" and "errfn", resp. The Process Manager call
1946 LaunchApplication is used to start the subprocess. We use high
1947 level events as the mechanism to pass arguments to the subprocess
1948 and to make Emacs wait for the subprocess to terminate and pass
1949 back a result code. The bulk of the code here packs the arguments
1950 into one message to be passed together with the high level event.
1951 Emacs also sometimes starts a subprocess using a shell to perform
1952 wildcard filename expansion. Since we don't really have a shell on
1953 the Mac, this case is detected and the starting of the shell is
1954 by-passed. We really need to add code here to do filename
1955 expansion to support such functionality. */
1958 run_mac_command (argv
, workdir
, infn
, outfn
, errfn
)
1959 unsigned char **argv
;
1960 const char *workdir
;
1961 const char *infn
, *outfn
, *errfn
;
1963 #ifdef TARGET_API_MAC_CARBON
1965 #else /* not TARGET_API_MAC_CARBON */
1966 char macappname
[MAXPATHLEN
+1], macworkdir
[MAXPATHLEN
+1];
1967 char macinfn
[MAXPATHLEN
+1], macoutfn
[MAXPATHLEN
+1], macerrfn
[MAXPATHLEN
+1];
1968 int paramlen
, argc
, newargc
, j
, retries
;
1969 char **newargv
, *param
, *p
;
1972 LaunchParamBlockRec lpbr
;
1973 EventRecord send_event
, reply_event
;
1974 RgnHandle cursor_region_handle
;
1976 unsigned long ref_con
, len
;
1978 if (posix_to_mac_pathname (workdir
, macworkdir
, MAXPATHLEN
+1) == 0)
1980 if (posix_to_mac_pathname (infn
, macinfn
, MAXPATHLEN
+1) == 0)
1982 if (posix_to_mac_pathname (outfn
, macoutfn
, MAXPATHLEN
+1) == 0)
1984 if (posix_to_mac_pathname (errfn
, macerrfn
, MAXPATHLEN
+1) == 0)
1987 paramlen
= strlen (macworkdir
) + strlen (macinfn
) + strlen (macoutfn
)
1988 + strlen (macerrfn
) + 4; /* count nulls at end of strings */
1997 /* If a subprocess is invoked with a shell, we receive 3 arguments
1998 of the form: "<path to emacs bins>/sh" "-c" "<path to emacs
1999 bins>/<command> <command args>" */
2000 j
= strlen (argv
[0]);
2001 if (j
>= 3 && strcmp (argv
[0]+j
-3, "/sh") == 0
2002 && argc
== 3 && strcmp (argv
[1], "-c") == 0)
2004 char *command
, *t
, tempmacpathname
[MAXPATHLEN
+1];
2006 /* The arguments for the command in argv[2] are separated by
2007 spaces. Count them and put the count in newargc. */
2008 command
= (char *) alloca (strlen (argv
[2])+2);
2009 strcpy (command
, argv
[2]);
2010 if (command
[strlen (command
) - 1] != ' ')
2011 strcat (command
, " ");
2015 t
= mystrchr (t
, ' ');
2019 t
= mystrchr (t
+1, ' ');
2022 newargv
= (char **) alloca (sizeof (char *) * newargc
);
2025 for (j
= 0; j
< newargc
; j
++)
2027 newargv
[j
] = (char *) alloca (strlen (t
) + 1);
2028 mystrcpy (newargv
[j
], t
);
2031 paramlen
+= strlen (newargv
[j
]) + 1;
2034 if (strncmp (newargv
[0], "~emacs/", 7) == 0)
2036 if (posix_to_mac_pathname (newargv
[0], tempmacpathname
, MAXPATHLEN
+1)
2041 { /* sometimes Emacs call "sh" without a path for the command */
2043 char *t
= (char *) alloca (strlen (newargv
[0]) + 7 + 1);
2044 strcpy (t
, "~emacs/");
2045 strcat (t
, newargv
[0]);
2048 openp (Vexec_path
, build_string (newargv
[0]), EXEC_SUFFIXES
, &path
,
2049 make_number (X_OK
));
2053 if (posix_to_mac_pathname (SDATA (path
), tempmacpathname
,
2057 strcpy (macappname
, tempmacpathname
);
2061 if (posix_to_mac_pathname (argv
[0], macappname
, MAXPATHLEN
+1) == 0)
2064 newargv
= (char **) alloca (sizeof (char *) * argc
);
2066 for (j
= 1; j
< argc
; j
++)
2068 if (strncmp (argv
[j
], "~emacs/", 7) == 0)
2070 char *t
= strchr (argv
[j
], ' ');
2073 char tempcmdname
[MAXPATHLEN
+1], tempmaccmdname
[MAXPATHLEN
+1];
2074 strncpy (tempcmdname
, argv
[j
], t
-argv
[j
]);
2075 tempcmdname
[t
-argv
[j
]] = '\0';
2076 if (posix_to_mac_pathname (tempcmdname
, tempmaccmdname
,
2079 newargv
[j
] = (char *) alloca (strlen (tempmaccmdname
)
2081 strcpy (newargv
[j
], tempmaccmdname
);
2082 strcat (newargv
[j
], t
);
2086 char tempmaccmdname
[MAXPATHLEN
+1];
2087 if (posix_to_mac_pathname (argv
[j
], tempmaccmdname
,
2090 newargv
[j
] = (char *) alloca (strlen (tempmaccmdname
)+1);
2091 strcpy (newargv
[j
], tempmaccmdname
);
2095 newargv
[j
] = argv
[j
];
2096 paramlen
+= strlen (newargv
[j
]) + 1;
2100 /* After expanding all the arguments, we now know the length of the
2101 parameter block to be sent to the subprocess as a message
2102 attached to the HLE. */
2103 param
= (char *) malloc (paramlen
+ 1);
2109 /* first byte of message contains number of arguments for command */
2110 strcpy (p
, macworkdir
);
2111 p
+= strlen (macworkdir
);
2113 /* null terminate strings sent so it's possible to use strcpy over there */
2114 strcpy (p
, macinfn
);
2115 p
+= strlen (macinfn
);
2117 strcpy (p
, macoutfn
);
2118 p
+= strlen (macoutfn
);
2120 strcpy (p
, macerrfn
);
2121 p
+= strlen (macerrfn
);
2123 for (j
= 1; j
< newargc
; j
++)
2125 strcpy (p
, newargv
[j
]);
2126 p
+= strlen (newargv
[j
]);
2130 c2pstr (macappname
);
2132 iErr
= FSMakeFSSpec (0, 0, macappname
, &spec
);
2140 lpbr
.launchBlockID
= extendedBlock
;
2141 lpbr
.launchEPBLength
= extendedBlockLen
;
2142 lpbr
.launchControlFlags
= launchContinue
+ launchNoFileFlags
;
2143 lpbr
.launchAppSpec
= &spec
;
2144 lpbr
.launchAppParameters
= NULL
;
2146 iErr
= LaunchApplication (&lpbr
); /* call the subprocess */
2153 send_event
.what
= kHighLevelEvent
;
2154 send_event
.message
= kEmacsSubprocessSend
;
2155 /* Event ID stored in "where" unused */
2158 /* OS may think current subprocess has terminated if previous one
2159 terminated recently. */
2162 iErr
= PostHighLevelEvent (&send_event
, &lpbr
.launchProcessSN
, 0, param
,
2163 paramlen
+ 1, receiverIDisPSN
);
2165 while (iErr
== sessClosedErr
&& retries
-- > 0);
2173 cursor_region_handle
= NewRgn ();
2175 /* Wait for the subprocess to finish, when it will send us a ERPY
2176 high level event. */
2178 if (WaitNextEvent (highLevelEventMask
, &reply_event
, 180,
2179 cursor_region_handle
)
2180 && reply_event
.message
== kEmacsSubprocessReply
)
2183 /* The return code is sent through the refCon */
2184 iErr
= AcceptHighLevelEvent (&targ
, &ref_con
, NULL
, &len
);
2187 DisposeHandle ((Handle
) cursor_region_handle
);
2192 DisposeHandle ((Handle
) cursor_region_handle
);
2196 #endif /* not TARGET_API_MAC_CARBON */
2201 opendir (const char *dirname
)
2203 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
2204 char mac_pathname
[MAXPATHLEN
+1], vol_name
[MAXPATHLEN
+1];
2208 int len
, vol_name_len
;
2210 if (find_true_pathname (dirname
, true_pathname
, MAXPATHLEN
+1) == -1)
2213 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
2215 fully_resolved_name
[len
] = '\0';
2217 strcpy (fully_resolved_name
, true_pathname
);
2219 dirp
= (DIR *) malloc (sizeof(DIR));
2223 /* Handle special case when dirname is "/": sets up for readir to
2224 get all mount volumes. */
2225 if (strcmp (fully_resolved_name
, "/") == 0)
2227 dirp
->getting_volumes
= 1; /* special all mounted volumes DIR struct */
2228 dirp
->current_index
= 1; /* index for first volume */
2232 /* Handle typical cases: not accessing all mounted volumes. */
2233 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
2236 /* Emacs calls opendir without the trailing '/', Mac needs trailing ':' */
2237 len
= strlen (mac_pathname
);
2238 if (mac_pathname
[len
- 1] != ':' && len
< MAXPATHLEN
)
2239 strcat (mac_pathname
, ":");
2241 /* Extract volume name */
2242 vol_name_len
= strchr (mac_pathname
, ':') - mac_pathname
;
2243 strncpy (vol_name
, mac_pathname
, vol_name_len
);
2244 vol_name
[vol_name_len
] = '\0';
2245 strcat (vol_name
, ":");
2247 c2pstr (mac_pathname
);
2248 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
2249 /* using full pathname so vRefNum and DirID ignored */
2250 cipb
.hFileInfo
.ioVRefNum
= 0;
2251 cipb
.hFileInfo
.ioDirID
= 0;
2252 cipb
.hFileInfo
.ioFDirIndex
= 0;
2253 /* set to 0 to get information about specific dir or file */
2255 errno
= PBGetCatInfo (&cipb
, false);
2262 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x10)) /* bit 4 = 1 for directories */
2263 return 0; /* not a directory */
2265 dirp
->dir_id
= cipb
.dirInfo
.ioDrDirID
; /* used later in readdir */
2266 dirp
->getting_volumes
= 0;
2267 dirp
->current_index
= 1; /* index for first file/directory */
2270 vpb
.ioNamePtr
= vol_name
;
2271 /* using full pathname so vRefNum and DirID ignored */
2273 vpb
.ioVolIndex
= -1;
2274 errno
= PBHGetVInfo ((union HParamBlockRec
*) &vpb
, false);
2281 dirp
->vol_ref_num
= vpb
.ioVRefNum
;
2298 HParamBlockRec hpblock
;
2300 static struct dirent s_dirent
;
2301 static Str255 s_name
;
2305 /* Handle the root directory containing the mounted volumes. Call
2306 PBHGetVInfo specifying an index to obtain the info for a volume.
2307 PBHGetVInfo returns an error when it receives an index beyond the
2308 last volume, at which time we should return a nil dirent struct
2310 if (dp
->getting_volumes
)
2312 hpblock
.volumeParam
.ioNamePtr
= s_name
;
2313 hpblock
.volumeParam
.ioVRefNum
= 0;
2314 hpblock
.volumeParam
.ioVolIndex
= dp
->current_index
;
2316 errno
= PBHGetVInfo (&hpblock
, false);
2324 strcat (s_name
, "/"); /* need "/" for stat to work correctly */
2326 dp
->current_index
++;
2328 s_dirent
.d_ino
= hpblock
.volumeParam
.ioVRefNum
;
2329 s_dirent
.d_name
= s_name
;
2335 cipb
.hFileInfo
.ioVRefNum
= dp
->vol_ref_num
;
2336 cipb
.hFileInfo
.ioNamePtr
= s_name
;
2337 /* location to receive filename returned */
2339 /* return only visible files */
2343 cipb
.hFileInfo
.ioDirID
= dp
->dir_id
;
2344 /* directory ID found by opendir */
2345 cipb
.hFileInfo
.ioFDirIndex
= dp
->current_index
;
2347 errno
= PBGetCatInfo (&cipb
, false);
2354 /* insist on a visible entry */
2355 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* directory? */
2356 done
= !(cipb
.dirInfo
.ioDrUsrWds
.frFlags
& fInvisible
);
2358 done
= !(cipb
.hFileInfo
.ioFlFndrInfo
.fdFlags
& fInvisible
);
2360 dp
->current_index
++;
2373 s_dirent
.d_ino
= cipb
.dirInfo
.ioDrDirID
;
2374 /* value unimportant: non-zero for valid file */
2375 s_dirent
.d_name
= s_name
;
2385 char mac_pathname
[MAXPATHLEN
+1];
2386 Str255 directory_name
;
2390 if (path_from_vol_dir_name (mac_pathname
, 255, 0, 0, "\p") == 0)
2393 if (mac_to_posix_pathname (mac_pathname
, path
, MAXPATHLEN
+1) == 0)
2399 #endif /* ! MAC_OSX */
2403 initialize_applescript ()
2408 /* if open fails, as_scripting_component is set to NULL. Its
2409 subsequent use in OSA calls will fail with badComponentInstance
2411 as_scripting_component
= OpenDefaultComponent (kOSAComponentType
,
2412 kAppleScriptSubtype
);
2414 null_desc
.descriptorType
= typeNull
;
2415 null_desc
.dataHandle
= 0;
2416 osaerror
= OSAMakeContext (as_scripting_component
, &null_desc
,
2417 kOSANullScript
, &as_script_context
);
2419 as_script_context
= kOSANullScript
;
2420 /* use default context if create fails */
2424 void terminate_applescript()
2426 OSADispose (as_scripting_component
, as_script_context
);
2427 CloseComponent (as_scripting_component
);
2431 /* Compile and execute the AppleScript SCRIPT and return the error
2432 status as function value. A zero is returned if compilation and
2433 execution is successful, in which case RESULT returns a pointer to
2434 a string containing the resulting script value. Otherwise, the Mac
2435 error code is returned and RESULT returns a pointer to an error
2436 string. In both cases the caller should deallocate the storage
2437 used by the string pointed to by RESULT if it is non-NULL. For
2438 documentation on the MacOS scripting architecture, see Inside
2439 Macintosh - Interapplication Communications: Scripting Components. */
2442 do_applescript (char *script
, char **result
)
2444 AEDesc script_desc
, result_desc
, error_desc
;
2451 if (!as_scripting_component
)
2452 initialize_applescript();
2454 error
= AECreateDesc (typeChar
, script
, strlen(script
), &script_desc
);
2458 osaerror
= OSADoScript (as_scripting_component
, &script_desc
, kOSANullScript
,
2459 typeChar
, kOSAModeNull
, &result_desc
);
2461 if (osaerror
== errOSAScriptError
)
2463 /* error executing AppleScript: retrieve error message */
2464 if (!OSAScriptError (as_scripting_component
, kOSAErrorMessage
, typeChar
,
2467 #if TARGET_API_MAC_CARBON
2468 length
= AEGetDescDataSize (&error_desc
);
2469 *result
= (char *) xmalloc (length
+ 1);
2472 AEGetDescData (&error_desc
, *result
, length
);
2473 *(*result
+ length
) = '\0';
2475 #else /* not TARGET_API_MAC_CARBON */
2476 HLock (error_desc
.dataHandle
);
2477 length
= GetHandleSize(error_desc
.dataHandle
);
2478 *result
= (char *) xmalloc (length
+ 1);
2481 memcpy (*result
, *(error_desc
.dataHandle
), length
);
2482 *(*result
+ length
) = '\0';
2484 HUnlock (error_desc
.dataHandle
);
2485 #endif /* not TARGET_API_MAC_CARBON */
2486 AEDisposeDesc (&error_desc
);
2489 else if (osaerror
== noErr
) /* success: retrieve resulting script value */
2491 #if TARGET_API_MAC_CARBON
2492 length
= AEGetDescDataSize (&result_desc
);
2493 *result
= (char *) xmalloc (length
+ 1);
2496 AEGetDescData (&result_desc
, *result
, length
);
2497 *(*result
+ length
) = '\0';
2499 #else /* not TARGET_API_MAC_CARBON */
2500 HLock (result_desc
.dataHandle
);
2501 length
= GetHandleSize(result_desc
.dataHandle
);
2502 *result
= (char *) xmalloc (length
+ 1);
2505 memcpy (*result
, *(result_desc
.dataHandle
), length
);
2506 *(*result
+ length
) = '\0';
2508 HUnlock (result_desc
.dataHandle
);
2509 #endif /* not TARGET_API_MAC_CARBON */
2510 AEDisposeDesc (&result_desc
);
2513 AEDisposeDesc (&script_desc
);
2519 DEFUN ("do-applescript", Fdo_applescript
, Sdo_applescript
, 1, 1, 0,
2520 doc
: /* Compile and execute AppleScript SCRIPT and retrieve and return the result.
2521 If compilation and execution are successful, the resulting script
2522 value is returned as a string. Otherwise the function aborts and
2523 displays the error message returned by the AppleScript scripting
2528 char *result
, *temp
;
2529 Lisp_Object lisp_result
;
2532 CHECK_STRING (script
);
2534 status
= do_applescript (SDATA (script
), &result
);
2538 error ("AppleScript error %d", status
);
2541 /* Unfortunately only OSADoScript in do_applescript knows how
2542 how large the resulting script value or error message is
2543 going to be and therefore as caller memory must be
2544 deallocated here. It is necessary to free the error
2545 message before calling error to avoid a memory leak. */
2546 temp
= (char *) alloca (strlen (result
) + 1);
2547 strcpy (temp
, result
);
2554 lisp_result
= build_string (result
);
2561 DEFUN ("mac-file-name-to-posix", Fmac_file_name_to_posix
,
2562 Smac_file_name_to_posix
, 1, 1, 0,
2563 doc
: /* Convert Macintosh filename to Posix form. */)
2565 Lisp_Object mac_filename
;
2567 char posix_filename
[MAXPATHLEN
+1];
2569 CHECK_STRING (mac_filename
);
2571 if (mac_to_posix_pathname (SDATA (mac_filename
), posix_filename
,
2573 return build_string (posix_filename
);
2579 DEFUN ("posix-file-name-to-mac", Fposix_file_name_to_mac
,
2580 Sposix_file_name_to_mac
, 1, 1, 0,
2581 doc
: /* Convert Posix filename to Mac form. */)
2583 Lisp_Object posix_filename
;
2585 char mac_filename
[MAXPATHLEN
+1];
2587 CHECK_STRING (posix_filename
);
2589 if (posix_to_mac_pathname (SDATA (posix_filename
), mac_filename
,
2591 return build_string (mac_filename
);
2597 /* set interprogram-paste-function to mac-paste-function in mac-win.el
2598 to enable Emacs to obtain the contents of the Mac clipboard. */
2599 DEFUN ("mac-paste-function", Fmac_paste_function
, Smac_paste_function
, 0, 0, 0,
2600 doc
: /* Return the contents of the Mac clipboard as a string. */)
2603 #if TARGET_API_MAC_CARBON
2605 ScrapFlavorFlags sff
;
2610 if (GetCurrentScrap (&scrap
) != noErr
)
2613 if (GetScrapFlavorFlags (scrap
, kScrapFlavorTypeText
, &sff
) != noErr
)
2616 if (GetScrapFlavorSize (scrap
, kScrapFlavorTypeText
, &s
) != noErr
)
2619 if ((data
= (char*) alloca (s
)) == NULL
)
2622 if (GetScrapFlavorData (scrap
, kScrapFlavorTypeText
, &s
, data
) != noErr
2626 /* Emacs expects clipboard contents have Unix-style eol's */
2627 for (i
= 0; i
< s
; i
++)
2628 if (data
[i
] == '\r')
2631 return make_string (data
, s
);
2632 #else /* not TARGET_API_MAC_CARBON */
2635 long scrap_offset
, rc
, i
;
2637 my_handle
= NewHandle (0); /* allocate 0-length data area */
2639 rc
= GetScrap (my_handle
, 'TEXT', &scrap_offset
);
2645 /* Emacs expects clipboard contents have Unix-style eol's */
2646 for (i
= 0; i
< rc
; i
++)
2647 if ((*my_handle
)[i
] == '\r')
2648 (*my_handle
)[i
] = '\n';
2650 value
= make_string (*my_handle
, rc
);
2652 HUnlock (my_handle
);
2654 DisposeHandle (my_handle
);
2657 #endif /* not TARGET_API_MAC_CARBON */
2661 /* set interprogram-cut-function to mac-cut-function in mac-win.el
2662 to enable Emacs to write the top of the kill-ring to the Mac clipboard. */
2663 DEFUN ("mac-cut-function", Fmac_cut_function
, Smac_cut_function
, 1, 2, 0,
2664 doc
: /* Put the value of the string parameter to the Mac clipboard. */)
2666 Lisp_Object value
, push
;
2671 /* fixme: ignore the push flag for now */
2673 CHECK_STRING (value
);
2675 len
= SCHARS (value
);
2676 buf
= (char *) alloca (len
+1);
2677 bcopy (SDATA (value
), buf
, len
);
2680 /* convert to Mac-style eol's before sending to clipboard */
2681 for (i
= 0; i
< len
; i
++)
2685 #if TARGET_API_MAC_CARBON
2688 ClearCurrentScrap ();
2689 if (GetCurrentScrap (&scrap
) != noErr
)
2690 error ("cannot get current scrap");
2692 if (PutScrapFlavor (scrap
, kScrapFlavorTypeText
, kScrapFlavorMaskNone
, len
,
2694 error ("cannot put to scrap");
2696 #else /* not TARGET_API_MAC_CARBON */
2698 PutScrap (len
, 'TEXT', buf
);
2699 #endif /* not TARGET_API_MAC_CARBON */
2705 DEFUN ("x-selection-exists-p", Fx_selection_exists_p
, Sx_selection_exists_p
,
2707 doc
: /* Whether there is an owner for the given X Selection.
2708 The arg should be the name of the selection in question, typically one of
2709 the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.
2710 \(Those are literal upper-case symbol names, since that's what X expects.)
2711 For convenience, the symbol nil is the same as `PRIMARY',
2712 and t is the same as `SECONDARY'. */)
2714 Lisp_Object selection
;
2716 CHECK_SYMBOL (selection
);
2718 /* Return nil for PRIMARY and SECONDARY selections; for CLIPBOARD, check
2719 if the clipboard currently has valid text format contents. */
2721 if (EQ (selection
, QCLIPBOARD
))
2723 Lisp_Object val
= Qnil
;
2725 #if TARGET_API_MAC_CARBON
2727 ScrapFlavorFlags sff
;
2729 if (GetCurrentScrap (&scrap
) == noErr
)
2730 if (GetScrapFlavorFlags (scrap
, kScrapFlavorTypeText
, &sff
) == noErr
)
2732 #else /* not TARGET_API_MAC_CARBON */
2734 long rc
, scrap_offset
;
2736 my_handle
= NewHandle (0);
2738 rc
= GetScrap (my_handle
, 'TEXT', &scrap_offset
);
2742 DisposeHandle (my_handle
);
2743 #endif /* not TARGET_API_MAC_CARBON */
2753 extern int inhibit_window_system
;
2755 /* When Emacs is started from the Finder, SELECT always immediately
2756 returns as if input is present when file descriptor 0 is polled for
2757 input. Strangely, when Emacs is run as a GUI application from the
2758 command line, it blocks in the same situation. This `wrapper' of
2759 the system call SELECT corrects this discrepancy. */
2761 sys_select (n
, rfds
, wfds
, efds
, timeout
)
2766 struct timeval
*timeout
;
2768 if (!inhibit_window_system
&& rfds
&& FD_ISSET (0, rfds
))
2771 return select (n
, rfds
, wfds
, efds
, timeout
);
2775 /* Set up environment variables so that Emacs can correctly find its
2776 support files when packaged as an application bundle. Directories
2777 placed in /usr/local/share/emacs/<emacs-version>/, /usr/local/bin,
2778 and /usr/local/libexec/emacs/<emacs-version>/<system-configuration>
2779 by `make install' by default can instead be placed in
2780 .../Emacs.app/Contents/Resources/ and
2781 .../Emacs.app/Contents/MacOS/. Each of these environment variables
2782 is changed only if it is not already set. Presumably if the user
2783 sets an environment variable, he will want to use files in his path
2784 instead of ones in the application bundle. */
2786 init_mac_osx_environment ()
2790 CFStringRef cf_app_bundle_pathname
;
2791 int app_bundle_pathname_len
;
2792 char *app_bundle_pathname
;
2796 /* Fetch the pathname of the application bundle as a C string into
2797 app_bundle_pathname. */
2799 bundle
= CFBundleGetMainBundle ();
2803 bundleURL
= CFBundleCopyBundleURL (bundle
);
2807 cf_app_bundle_pathname
= CFURLCopyFileSystemPath (bundleURL
,
2808 kCFURLPOSIXPathStyle
);
2809 app_bundle_pathname_len
= CFStringGetLength (cf_app_bundle_pathname
);
2810 app_bundle_pathname
= (char *) alloca (app_bundle_pathname_len
+ 1);
2812 if (!CFStringGetCString (cf_app_bundle_pathname
,
2813 app_bundle_pathname
,
2814 app_bundle_pathname_len
+ 1,
2815 kCFStringEncodingISOLatin1
))
2817 CFRelease (cf_app_bundle_pathname
);
2821 CFRelease (cf_app_bundle_pathname
);
2823 /* P should have sufficient room for the pathname of the bundle plus
2824 the subpath in it leading to the respective directories. Q
2825 should have three times that much room because EMACSLOADPATH can
2826 have the value "<path to lisp dir>:<path to leim dir>:<path to
2828 p
= (char *) alloca (app_bundle_pathname_len
+ 50);
2829 q
= (char *) alloca (3 * app_bundle_pathname_len
+ 150);
2830 if (!getenv ("EMACSLOADPATH"))
2834 strcpy (p
, app_bundle_pathname
);
2835 strcat (p
, "/Contents/Resources/lisp");
2836 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
2839 strcpy (p
, app_bundle_pathname
);
2840 strcat (p
, "/Contents/Resources/leim");
2841 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
2848 strcpy (p
, app_bundle_pathname
);
2849 strcat (p
, "/Contents/Resources/site-lisp");
2850 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
2858 setenv ("EMACSLOADPATH", q
, 1);
2861 if (!getenv ("EMACSPATH"))
2865 strcpy (p
, app_bundle_pathname
);
2866 strcat (p
, "/Contents/MacOS/bin");
2867 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
2870 strcpy (p
, app_bundle_pathname
);
2871 strcat (p
, "/Contents/MacOS/libexec");
2872 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
2880 setenv ("EMACSPATH", q
, 1);
2883 if (!getenv ("EMACSDATA"))
2885 strcpy (p
, app_bundle_pathname
);
2886 strcat (p
, "/Contents/Resources/etc");
2887 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
2888 setenv ("EMACSDATA", p
, 1);
2891 if (!getenv ("EMACSDOC"))
2893 strcpy (p
, app_bundle_pathname
);
2894 strcat (p
, "/Contents/Resources/etc");
2895 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
2896 setenv ("EMACSDOC", p
, 1);
2899 if (!getenv ("INFOPATH"))
2901 strcpy (p
, app_bundle_pathname
);
2902 strcat (p
, "/Contents/Resources/info");
2903 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
2904 setenv ("INFOPATH", p
, 1);
2907 #endif /* MAC_OSX */
2912 QCLIPBOARD
= intern ("CLIPBOARD");
2913 staticpro (&QCLIPBOARD
);
2915 defsubr (&Smac_paste_function
);
2916 defsubr (&Smac_cut_function
);
2917 defsubr (&Sx_selection_exists_p
);
2919 defsubr (&Sdo_applescript
);
2920 defsubr (&Smac_file_name_to_posix
);
2921 defsubr (&Sposix_file_name_to_mac
);