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). */
32 #include <sys/param.h>
44 #include <Carbon/Carbon.h>
46 #define free unexec_free
48 #define malloc unexec_malloc
50 #define realloc unexec_realloc
52 #define init_process emacs_init_process
53 #else /* not MAC_OSX */
56 #include <TextUtils.h>
58 #include <Resources.h>
63 #include <AppleScript.h>
65 #endif /* not MAC_OSX */
69 #include "sysselect.h"
72 Lisp_Object QCLIPBOARD
;
74 /* An instance of the AppleScript component. */
75 static ComponentInstance as_scripting_component
;
76 /* The single script context used for all script executions. */
77 static OSAID as_script_context
;
80 /* When converting from Mac to Unix pathnames, /'s in folder names are
81 converted to :'s. This function, used in copying folder names,
82 performs a strncat and converts all character a to b in the copy of
83 the string s2 appended to the end of s1. */
86 string_cat_and_replace (char *s1
, const char *s2
, int n
, char a
, char b
)
94 for (i
= 0; i
< l2
; i
++)
103 /* Convert a Mac pathname to Posix form. A Mac full pathname is one
104 that does not begin with a ':' and contains at least one ':'. A Mac
105 full pathname causes an '/' to be prepended to the Posix pathname.
106 The algorithm for the rest of the pathname is as follows:
107 For each segment between two ':',
108 if it is non-null, copy as is and then add a '/' at the end,
109 otherwise, insert a "../" into the Posix pathname.
110 Returns 1 if successful; 0 if fails. */
113 mac_to_posix_pathname (const char *mfn
, char *ufn
, int ufnbuflen
)
115 const char *p
, *q
, *pe
;
122 p
= strchr (mfn
, ':');
123 if (p
!= 0 && p
!= mfn
) /* full pathname */
130 pe
= mfn
+ strlen (mfn
);
137 { /* two consecutive ':' */
138 if (strlen (ufn
) + 3 >= ufnbuflen
)
144 if (strlen (ufn
) + (q
- p
) + 1 >= ufnbuflen
)
146 string_cat_and_replace (ufn
, p
, q
- p
, '/', ':');
153 if (strlen (ufn
) + (pe
- p
) >= ufnbuflen
)
155 string_cat_and_replace (ufn
, p
, pe
- p
, '/', ':');
156 /* no separator for last one */
165 extern char *get_temp_dir_name ();
168 /* Convert a Posix pathname to Mac form. Approximately reverse of the
169 above in algorithm. */
172 posix_to_mac_pathname (const char *ufn
, char *mfn
, int mfnbuflen
)
174 const char *p
, *q
, *pe
;
175 char expanded_pathname
[MAXPATHLEN
+1];
184 /* Check for and handle volume names. Last comparison: strangely
185 somewhere "/.emacs" is passed. A temporary fix for now. */
186 if (*p
== '/' && strchr (p
+1, '/') == NULL
&& strcmp (p
, "/.emacs") != 0)
188 if (strlen (p
) + 1 > mfnbuflen
)
195 /* expand to emacs dir found by init_emacs_passwd_dir */
196 if (strncmp (p
, "~emacs/", 7) == 0)
198 struct passwd
*pw
= getpwnam ("emacs");
200 if (strlen (pw
->pw_dir
) + strlen (p
) > MAXPATHLEN
)
202 strcpy (expanded_pathname
, pw
->pw_dir
);
203 strcat (expanded_pathname
, p
);
204 p
= expanded_pathname
;
205 /* now p points to the pathname with emacs dir prefix */
207 else if (strncmp (p
, "/tmp/", 5) == 0)
209 char *t
= get_temp_dir_name ();
211 if (strlen (t
) + strlen (p
) > MAXPATHLEN
)
213 strcpy (expanded_pathname
, t
);
214 strcat (expanded_pathname
, p
);
215 p
= expanded_pathname
;
216 /* now p points to the pathname with emacs dir prefix */
218 else if (*p
!= '/') /* relative pathname */
230 if (q
- p
== 2 && *p
== '.' && *(p
+1) == '.')
232 if (strlen (mfn
) + 1 >= mfnbuflen
)
238 if (strlen (mfn
) + (q
- p
) + 1 >= mfnbuflen
)
240 string_cat_and_replace (mfn
, p
, q
- p
, ':', '/');
247 if (strlen (mfn
) + (pe
- p
) >= mfnbuflen
)
249 string_cat_and_replace (mfn
, p
, pe
- p
, ':', '/');
259 /* The following functions with "sys_" prefix are stubs to Unix
260 functions that have already been implemented by CW or MPW. The
261 calls to them in Emacs source course are #define'd to call the sys_
262 versions by the header files s-mac.h. In these stubs pathnames are
263 converted between their Unix and Mac forms. */
266 /* Unix epoch is Jan 1, 1970 while Mac epoch is Jan 1, 1904: 66 years
267 + 17 leap days. These are for adjusting time values returned by
268 MacOS Toolbox functions. */
270 #define MAC_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
274 /* CW Pro 5 epoch is Jan 1, 1900 (aaarghhhhh!); remember, 1900 is not
275 a leap year! This is for adjusting time_t values returned by MSL
277 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 70 + 17) * 24 * 60 * 60)
278 #else /* __MSL__ >= 0x6000 */
279 /* CW changes Pro 6 to follow Unix! */
280 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
281 #endif /* __MSL__ >= 0x6000 */
283 /* MPW library functions follow Unix (confused?). */
284 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
285 #else /* not __MRC__ */
287 #endif /* not __MRC__ */
290 /* Define our own stat function for both MrC and CW. The reason for
291 doing this: "stat" is both the name of a struct and function name:
292 can't use the same trick like that for sys_open, sys_close, etc. to
293 redirect Emacs's calls to our own version that converts Unix style
294 filenames to Mac style filename because all sorts of compilation
295 errors will be generated if stat is #define'd to be sys_stat. */
298 stat_noalias (const char *path
, struct stat
*buf
)
300 char mac_pathname
[MAXPATHLEN
+1];
303 if (posix_to_mac_pathname (path
, mac_pathname
, MAXPATHLEN
+1) == 0)
306 c2pstr (mac_pathname
);
307 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
308 cipb
.hFileInfo
.ioVRefNum
= 0;
309 cipb
.hFileInfo
.ioDirID
= 0;
310 cipb
.hFileInfo
.ioFDirIndex
= 0;
311 /* set to 0 to get information about specific dir or file */
313 errno
= PBGetCatInfo (&cipb
, false);
314 if (errno
== -43) /* -43: fnfErr defined in Errors.h */
319 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* bit 4 = 1 for directories */
321 buf
->st_mode
= S_IFDIR
| S_IREAD
| S_IEXEC
;
323 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x1))
324 buf
->st_mode
|= S_IWRITE
; /* bit 1 = 1 for locked files/directories */
325 buf
->st_ino
= cipb
.dirInfo
.ioDrDirID
;
326 buf
->st_dev
= cipb
.dirInfo
.ioVRefNum
;
327 buf
->st_size
= cipb
.dirInfo
.ioDrNmFls
;
328 /* size of dir = number of files and dirs */
331 = cipb
.dirInfo
.ioDrMdDat
- MAC_UNIX_EPOCH_DIFF
;
332 buf
->st_ctime
= cipb
.dirInfo
.ioDrCrDat
- MAC_UNIX_EPOCH_DIFF
;
336 buf
->st_mode
= S_IFREG
| S_IREAD
;
337 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x1))
338 buf
->st_mode
|= S_IWRITE
; /* bit 1 = 1 for locked files/directories */
339 if (cipb
.hFileInfo
.ioFlFndrInfo
.fdType
== 'APPL')
340 buf
->st_mode
|= S_IEXEC
;
341 buf
->st_ino
= cipb
.hFileInfo
.ioDirID
;
342 buf
->st_dev
= cipb
.hFileInfo
.ioVRefNum
;
343 buf
->st_size
= cipb
.hFileInfo
.ioFlLgLen
;
346 = cipb
.hFileInfo
.ioFlMdDat
- MAC_UNIX_EPOCH_DIFF
;
347 buf
->st_ctime
= cipb
.hFileInfo
.ioFlCrDat
- MAC_UNIX_EPOCH_DIFF
;
350 if (cipb
.hFileInfo
.ioFlFndrInfo
.fdFlags
& 0x8000)
352 /* identify alias files as symlinks */
353 buf
->st_mode
&= ~S_IFREG
;
354 buf
->st_mode
|= S_IFLNK
;
358 buf
->st_uid
= getuid ();
359 buf
->st_gid
= getgid ();
367 lstat (const char *path
, struct stat
*buf
)
370 char true_pathname
[MAXPATHLEN
+1];
372 /* Try looking for the file without resolving aliases first. */
373 if ((result
= stat_noalias (path
, buf
)) >= 0)
376 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
379 return stat_noalias (true_pathname
, buf
);
384 stat (const char *path
, struct stat
*sb
)
387 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
390 if ((result
= stat_noalias (path
, sb
)) >= 0 &&
391 ! (sb
->st_mode
& S_IFLNK
))
394 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
397 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
400 fully_resolved_name
[len
] = '\0';
401 /* in fact our readlink terminates strings */
402 return lstat (fully_resolved_name
, sb
);
405 return lstat (true_pathname
, sb
);
410 /* CW defines fstat in stat.mac.c while MPW does not provide this
411 function. Without the information of how to get from a file
412 descriptor in MPW StdCLib to a Mac OS file spec, it should be hard
413 to implement this function. Fortunately, there is only one place
414 where this function is called in our configuration: in fileio.c,
415 where only the st_dev and st_ino fields are used to determine
416 whether two fildes point to different i-nodes to prevent copying
417 a file onto itself equal. What we have here probably needs
421 fstat (int fildes
, struct stat
*buf
)
424 buf
->st_ino
= fildes
;
425 buf
->st_mode
= S_IFREG
; /* added by T.I. for the copy-file */
426 return 0; /* success */
432 mkdir (const char *dirname
, int mode
)
437 char true_pathname
[MAXPATHLEN
+1], mac_pathname
[MAXPATHLEN
+1];
439 if (find_true_pathname (dirname
, true_pathname
, MAXPATHLEN
+1) == -1)
442 if (posix_to_mac_pathname (true_pathname
, mac_pathname
, MAXPATHLEN
+1) == 0)
445 c2pstr (mac_pathname
);
446 hfpb
.ioNamePtr
= mac_pathname
;
447 hfpb
.ioVRefNum
= 0; /* ignored unless name is invalid */
448 hfpb
.ioDirID
= 0; /* parent is the root */
450 errno
= PBDirCreate ((HParmBlkPtr
) &hfpb
, false);
451 /* just return the Mac OSErr code for now */
452 return errno
== noErr
? 0 : -1;
457 sys_rmdir (const char *dirname
)
460 char mac_pathname
[MAXPATHLEN
+1];
462 if (posix_to_mac_pathname (dirname
, mac_pathname
, MAXPATHLEN
+1) == 0)
465 c2pstr (mac_pathname
);
466 hfpb
.ioNamePtr
= mac_pathname
;
467 hfpb
.ioVRefNum
= 0; /* ignored unless name is invalid */
468 hfpb
.ioDirID
= 0; /* parent is the root */
470 errno
= PBHDelete ((HParmBlkPtr
) &hfpb
, false);
471 return errno
== noErr
? 0 : -1;
476 /* No implementation yet. */
478 execvp (const char *path
, ...)
486 utime (const char *path
, const struct utimbuf
*times
)
488 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
490 char mac_pathname
[MAXPATHLEN
+1];
493 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
496 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
498 fully_resolved_name
[len
] = '\0';
500 strcpy (fully_resolved_name
, true_pathname
);
502 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
505 c2pstr (mac_pathname
);
506 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
507 cipb
.hFileInfo
.ioVRefNum
= 0;
508 cipb
.hFileInfo
.ioDirID
= 0;
509 cipb
.hFileInfo
.ioFDirIndex
= 0;
510 /* set to 0 to get information about specific dir or file */
512 errno
= PBGetCatInfo (&cipb
, false);
516 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* bit 4 = 1 for directories */
519 cipb
.dirInfo
.ioDrMdDat
= times
->modtime
+ MAC_UNIX_EPOCH_DIFF
;
521 GetDateTime (&cipb
.dirInfo
.ioDrMdDat
);
526 cipb
.hFileInfo
.ioFlMdDat
= times
->modtime
+ MAC_UNIX_EPOCH_DIFF
;
528 GetDateTime (&cipb
.hFileInfo
.ioFlMdDat
);
531 errno
= PBSetCatInfo (&cipb
, false);
532 return errno
== noErr
? 0 : -1;
546 /* Like stat, but test for access mode in hfpb.ioFlAttrib */
548 access (const char *path
, int mode
)
550 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
552 char mac_pathname
[MAXPATHLEN
+1];
555 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
558 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
560 fully_resolved_name
[len
] = '\0';
562 strcpy (fully_resolved_name
, true_pathname
);
564 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
567 c2pstr (mac_pathname
);
568 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
569 cipb
.hFileInfo
.ioVRefNum
= 0;
570 cipb
.hFileInfo
.ioDirID
= 0;
571 cipb
.hFileInfo
.ioFDirIndex
= 0;
572 /* set to 0 to get information about specific dir or file */
574 errno
= PBGetCatInfo (&cipb
, false);
578 if (mode
== F_OK
) /* got this far, file exists */
582 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* path refers to a directory */
586 if (cipb
.hFileInfo
.ioFlFndrInfo
.fdType
== 'APPL')
593 return (cipb
.hFileInfo
.ioFlAttrib
& 0x1) ? -1 : 0;
594 /* don't allow if lock bit is on */
600 #define DEV_NULL_FD 0x10000
604 sys_open (const char *path
, int oflag
)
606 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
608 char mac_pathname
[MAXPATHLEN
+1];
610 if (strcmp (path
, "/dev/null") == 0)
611 return DEV_NULL_FD
; /* some bogus fd to be ignored in write */
613 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
616 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
618 fully_resolved_name
[len
] = '\0';
620 strcpy (fully_resolved_name
, true_pathname
);
622 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
627 int res
= open (mac_pathname
, oflag
);
628 /* if (oflag == O_WRONLY || oflag == O_RDWR) */
630 fsetfileinfo (mac_pathname
, 'EMAx', 'TEXT');
632 #else /* not __MRC__ */
633 return open (mac_pathname
, oflag
);
634 #endif /* not __MRC__ */
641 sys_creat (const char *path
, mode_t mode
)
643 char true_pathname
[MAXPATHLEN
+1];
645 char mac_pathname
[MAXPATHLEN
+1];
647 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
650 if (!posix_to_mac_pathname (true_pathname
, mac_pathname
, MAXPATHLEN
+1))
655 int result
= creat (mac_pathname
);
656 fsetfileinfo (mac_pathname
, 'EMAx', 'TEXT');
658 #else /* not __MRC__ */
659 return creat (mac_pathname
, mode
);
660 #endif /* not __MRC__ */
667 sys_unlink (const char *path
)
669 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
671 char mac_pathname
[MAXPATHLEN
+1];
673 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
676 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
678 fully_resolved_name
[len
] = '\0';
680 strcpy (fully_resolved_name
, true_pathname
);
682 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
685 return unlink (mac_pathname
);
691 sys_read (int fildes
, char *buf
, int count
)
693 if (fildes
== 0) /* this should not be used for console input */
696 #if __MSL__ >= 0x6000
697 return _read (fildes
, buf
, count
);
699 return read (fildes
, buf
, count
);
706 sys_write (int fildes
, const char *buf
, int count
)
708 if (fildes
== DEV_NULL_FD
)
711 #if __MSL__ >= 0x6000
712 return _write (fildes
, buf
, count
);
714 return write (fildes
, buf
, count
);
721 sys_rename (const char * old_name
, const char * new_name
)
723 char true_old_pathname
[MAXPATHLEN
+1], true_new_pathname
[MAXPATHLEN
+1];
724 char fully_resolved_old_name
[MAXPATHLEN
+1];
726 char mac_old_name
[MAXPATHLEN
+1], mac_new_name
[MAXPATHLEN
+1];
728 if (find_true_pathname (old_name
, true_old_pathname
, MAXPATHLEN
+1) == -1)
731 len
= readlink (true_old_pathname
, fully_resolved_old_name
, MAXPATHLEN
);
733 fully_resolved_old_name
[len
] = '\0';
735 strcpy (fully_resolved_old_name
, true_old_pathname
);
737 if (find_true_pathname (new_name
, true_new_pathname
, MAXPATHLEN
+1) == -1)
740 if (strcmp (fully_resolved_old_name
, true_new_pathname
) == 0)
743 if (!posix_to_mac_pathname (fully_resolved_old_name
,
748 if (!posix_to_mac_pathname(true_new_pathname
, mac_new_name
, MAXPATHLEN
+1))
751 /* If a file with new_name already exists, rename deletes the old
752 file in Unix. CW version fails in these situation. So we add a
753 call to unlink here. */
754 (void) unlink (mac_new_name
);
756 return rename (mac_old_name
, mac_new_name
);
761 extern FILE *fopen (const char *name
, const char *mode
);
763 sys_fopen (const char *name
, const char *mode
)
765 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
767 char mac_pathname
[MAXPATHLEN
+1];
769 if (find_true_pathname (name
, true_pathname
, MAXPATHLEN
+1) == -1)
772 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
774 fully_resolved_name
[len
] = '\0';
776 strcpy (fully_resolved_name
, true_pathname
);
778 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
783 if (mode
[0] == 'w' || mode
[0] == 'a')
784 fsetfileinfo (mac_pathname
, 'EMAx', 'TEXT');
785 #endif /* not __MRC__ */
786 return fopen (mac_pathname
, mode
);
793 long target_ticks
= 0;
796 __sigfun alarm_signal_func
= (__sigfun
) 0;
798 __signal_func_ptr alarm_signal_func
= (__signal_func_ptr
) 0;
799 #else /* not __MRC__ and not __MWERKS__ */
801 #endif /* not __MRC__ and not __MWERKS__ */
804 /* These functions simulate SIG_ALRM. The stub for function signal
805 stores the signal handler function in alarm_signal_func if a
806 SIG_ALRM is encountered. check_alarm is called in XTread_socket,
807 which emacs calls periodically. A pending alarm is represented by
808 a non-zero target_ticks value. check_alarm calls the handler
809 function pointed to by alarm_signal_func if one has been set up and
810 an alarm is pending. */
815 if (target_ticks
&& TickCount () > target_ticks
)
818 if (alarm_signal_func
)
819 (*alarm_signal_func
)(SIGALRM
);
825 select (n
, rfds
, wfds
, efds
, timeout
)
830 struct timeval
*timeout
;
832 #ifdef TARGET_API_MAC_CARBON
834 #else /* not TARGET_API_MAC_CARBON */
835 EMACS_TIME end_time
, now
;
838 /* Can only handle wait for keyboard input. */
839 if (n
> 1 || wfds
|| efds
)
842 EMACS_GET_TIME (end_time
);
843 EMACS_ADD_TIME (end_time
, end_time
, *timeout
);
847 /* Also return true if an event other than a keyDown has
848 occurred. This causes kbd_buffer_get_event in keyboard.c to
849 call read_avail_input which in turn calls XTread_socket to
850 poll for these events. Otherwise these never get processed
851 except but a very slow poll timer. */
852 if (FD_ISSET (0, rfds
) && EventAvail (everyEvent
, &e
))
855 /* Also check movement of the mouse. */
858 static Point old_mouse_pos
= {-1, -1};
860 GetMouse (&mouse_pos
);
861 if (!EqualPt (mouse_pos
, old_mouse_pos
))
863 old_mouse_pos
= mouse_pos
;
868 WaitNextEvent (0, &e
, 1UL, NULL
); /* Accept no event; wait 1
871 EMACS_GET_TIME (now
);
872 EMACS_SUB_TIME (now
, end_time
, now
);
874 while (!EMACS_TIME_NEG_P (now
));
877 #endif /* not TARGET_API_MAC_CARBON */
881 /* Called in sys_select to wait for an alarm signal to arrive. */
889 if (!target_ticks
) /* no alarm pending */
892 if ((tick
= TickCount ()) < target_ticks
)
893 WaitNextEvent (0, &e
, target_ticks
- tick
, NULL
); /* Accept no event;
894 just wait. by T.I. */
897 if (alarm_signal_func
)
898 (*alarm_signal_func
)(SIGALRM
);
907 long remaining
= target_ticks
? (TickCount () - target_ticks
) / 60 : 0;
909 target_ticks
= seconds
? TickCount () + 60 * seconds
: 0;
911 return (remaining
< 0) ? 0 : (unsigned int) remaining
;
917 extern __sigfun
signal (int signal
, __sigfun signal_func
);
919 sys_signal (int signal_num
, __sigfun signal_func
)
921 extern __signal_func_ptr
signal (int signal
, __signal_func_ptr signal_func
);
923 sys_signal (int signal_num
, __signal_func_ptr signal_func
)
924 #else /* not __MRC__ and not __MWERKS__ */
926 #endif /* not __MRC__ and not __MWERKS__ */
928 if (signal_num
!= SIGALRM
)
929 return signal (signal_num
, signal_func
);
933 __sigfun old_signal_func
;
935 __signal_func_ptr old_signal_func
;
939 old_signal_func
= alarm_signal_func
;
940 alarm_signal_func
= signal_func
;
941 return old_signal_func
;
946 /* gettimeofday should return the amount of time (in a timeval
947 structure) since midnight today. The toolbox function Microseconds
948 returns the number of microseconds (in a UnsignedWide value) since
949 the machine was booted. Also making this complicated is WideAdd,
950 WideSubtract, etc. take wide values. */
957 static wide wall_clock_at_epoch
, clicks_at_epoch
;
958 UnsignedWide uw_microseconds
;
960 time_t sys_time (time_t *);
962 /* If this function is called for the first time, record the number
963 of seconds since midnight and the number of microseconds since
964 boot at the time of this first call. */
969 systime
= sys_time (NULL
);
970 /* Store microseconds since midnight in wall_clock_at_epoch. */
971 WideMultiply (systime
, 1000000L, &wall_clock_at_epoch
);
972 Microseconds (&uw_microseconds
);
973 /* Store microseconds since boot in clicks_at_epoch. */
974 clicks_at_epoch
.hi
= uw_microseconds
.hi
;
975 clicks_at_epoch
.lo
= uw_microseconds
.lo
;
978 /* Get time since boot */
979 Microseconds (&uw_microseconds
);
981 /* Convert to time since midnight*/
982 w_microseconds
.hi
= uw_microseconds
.hi
;
983 w_microseconds
.lo
= uw_microseconds
.lo
;
984 WideSubtract (&w_microseconds
, &clicks_at_epoch
);
985 WideAdd (&w_microseconds
, &wall_clock_at_epoch
);
986 tp
->tv_sec
= WideDivide (&w_microseconds
, 1000000L, &tp
->tv_usec
);
994 sleep (unsigned int seconds
)
996 unsigned long time_up
;
999 time_up
= TickCount () + seconds
* 60;
1000 while (TickCount () < time_up
)
1002 /* Accept no event; just wait. by T.I. */
1003 WaitNextEvent (0, &e
, 30, NULL
);
1008 #endif /* __MRC__ */
1011 /* The time functions adjust time values according to the difference
1012 between the Unix and CW epoches. */
1015 extern struct tm
*gmtime (const time_t *);
1017 sys_gmtime (const time_t *timer
)
1019 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
1021 return gmtime (&unix_time
);
1026 extern struct tm
*localtime (const time_t *);
1028 sys_localtime (const time_t *timer
)
1030 #if __MSL__ >= 0x6000
1031 time_t unix_time
= *timer
;
1033 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
1036 return localtime (&unix_time
);
1041 extern char *ctime (const time_t *);
1043 sys_ctime (const time_t *timer
)
1045 #if __MSL__ >= 0x6000
1046 time_t unix_time
= *timer
;
1048 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
1051 return ctime (&unix_time
);
1056 extern time_t time (time_t *);
1058 sys_time (time_t *timer
)
1060 #if __MSL__ >= 0x6000
1061 time_t mac_time
= time (NULL
);
1063 time_t mac_time
= time (NULL
) - CW_OR_MPW_UNIX_EPOCH_DIFF
;
1073 /* MPW strftime broken for "%p" format */
1078 sys_strftime (char * s
, size_t maxsize
, const char * format
,
1079 const struct tm
* timeptr
)
1081 if (strcmp (format
, "%p") == 0)
1085 if (timeptr
->tm_hour
< 12)
1097 return strftime (s
, maxsize
, format
, timeptr
);
1099 #endif /* __MRC__ */
1102 /* no subprocesses, empty wait */
1112 croak (char *badfunc
)
1114 printf ("%s not yet implemented\r\n", badfunc
);
1120 index (const char * str
, int chr
)
1122 return strchr (str
, chr
);
1127 mktemp (char *template)
1132 len
= strlen (template);
1134 while (k
>= 0 && template[k
] == 'X')
1137 k
++; /* make k index of first 'X' */
1141 /* Zero filled, number of digits equal to the number of X's. */
1142 sprintf (&template[k
], "%0*d", len
-k
, seqnum
++);
1151 /* Emulate getpwuid, getpwnam and others. */
1153 #define PASSWD_FIELD_SIZE 256
1155 static char my_passwd_name
[PASSWD_FIELD_SIZE
];
1156 static char my_passwd_dir
[MAXPATHLEN
+1];
1158 static struct passwd my_passwd
=
1165 /* Initialized by main () in macterm.c to pathname of emacs directory. */
1167 char emacs_passwd_dir
[MAXPATHLEN
+1];
1173 init_emacs_passwd_dir ()
1177 if (getwd (emacs_passwd_dir
) && getwd (my_passwd_dir
))
1179 /* Need pathname of first ancestor that begins with "emacs"
1180 since Mac emacs application is somewhere in the emacs-*
1182 int len
= strlen (emacs_passwd_dir
);
1184 /* j points to the "/" following the directory name being
1187 while (i
>= 0 && !found
)
1189 while (i
>= 0 && emacs_passwd_dir
[i
] != '/')
1191 if (emacs_passwd_dir
[i
] == '/' && i
+5 < len
)
1192 found
= (strncmp (&(emacs_passwd_dir
[i
+1]), "emacs", 5) == 0);
1194 emacs_passwd_dir
[j
+1] = '\0';
1205 /* Setting to "/" probably won't work but set it to something
1207 strcpy (emacs_passwd_dir
, "/");
1208 strcpy (my_passwd_dir
, "/");
1213 static struct passwd emacs_passwd
=
1219 static int my_passwd_inited
= 0;
1227 /* Note: my_passwd_dir initialized in int_emacs_passwd_dir to
1228 directory where Emacs was started. */
1230 owner_name
= (char **) GetResource ('STR ',-16096);
1234 BlockMove ((unsigned char *) *owner_name
,
1235 (unsigned char *) my_passwd_name
,
1237 HUnlock (owner_name
);
1238 p2cstr ((unsigned char *) my_passwd_name
);
1241 my_passwd_name
[0] = 0;
1246 getpwuid (uid_t uid
)
1248 if (!my_passwd_inited
)
1251 my_passwd_inited
= 1;
1259 getpwnam (const char *name
)
1261 if (strcmp (name
, "emacs") == 0)
1262 return &emacs_passwd
;
1264 if (!my_passwd_inited
)
1267 my_passwd_inited
= 1;
1274 /* The functions fork, kill, sigsetmask, sigblock, request_sigio,
1275 setpgrp, setpriority, and unrequest_sigio are defined to be empty
1296 error ("Can't spawn subshell");
1315 request_sigio (void)
1321 unrequest_sigio (void)
1336 pipe (int _fildes
[2])
1343 /* Hard and symbolic links. */
1346 symlink (const char *name1
, const char *name2
)
1354 link (const char *name1
, const char *name2
)
1360 #endif /* ! MAC_OSX */
1362 /* Determine the path name of the file specified by VREFNUM, DIRID,
1363 and NAME and place that in the buffer PATH of length
1366 path_from_vol_dir_name (char *path
, int man_path_len
, short vol_ref_num
,
1367 long dir_id
, ConstStr255Param name
)
1373 if (strlen (name
) > man_path_len
)
1376 memcpy (dir_name
, name
, name
[0]+1);
1377 memcpy (path
, name
, name
[0]+1);
1380 cipb
.dirInfo
.ioDrParID
= dir_id
;
1381 cipb
.dirInfo
.ioNamePtr
= dir_name
;
1385 cipb
.dirInfo
.ioVRefNum
= vol_ref_num
;
1386 cipb
.dirInfo
.ioFDirIndex
= -1;
1387 cipb
.dirInfo
.ioDrDirID
= cipb
.dirInfo
.ioDrParID
;
1388 /* go up to parent each time */
1390 err
= PBGetCatInfo (&cipb
, false);
1395 if (strlen (dir_name
) + strlen (path
) + 1 >= man_path_len
)
1398 strcat (dir_name
, ":");
1399 strcat (dir_name
, path
);
1400 /* attach to front since we're going up directory tree */
1401 strcpy (path
, dir_name
);
1403 while (cipb
.dirInfo
.ioDrDirID
!= fsRtDirID
);
1404 /* stop when we see the volume's root directory */
1406 return 1; /* success */
1412 readlink (const char *path
, char *buf
, int bufsiz
)
1414 char mac_sym_link_name
[MAXPATHLEN
+1];
1417 Boolean target_is_folder
, was_aliased
;
1418 Str255 directory_name
, mac_pathname
;
1421 if (posix_to_mac_pathname (path
, mac_sym_link_name
, MAXPATHLEN
+1) == 0)
1424 c2pstr (mac_sym_link_name
);
1425 err
= FSMakeFSSpec (0, 0, mac_sym_link_name
, &fsspec
);
1432 err
= ResolveAliasFile (&fsspec
, true, &target_is_folder
, &was_aliased
);
1433 if (err
!= noErr
|| !was_aliased
)
1439 if (path_from_vol_dir_name (mac_pathname
, 255, fsspec
.vRefNum
, fsspec
.parID
,
1446 if (mac_to_posix_pathname (mac_pathname
, buf
, bufsiz
) == 0)
1452 return strlen (buf
);
1456 /* Convert a path to one with aliases fully expanded. */
1459 find_true_pathname (const char *path
, char *buf
, int bufsiz
)
1461 char *q
, temp
[MAXPATHLEN
+1];
1465 if (bufsiz
<= 0 || path
== 0 || path
[0] == '\0')
1472 q
= strchr (p
+ 1, '/');
1474 q
= strchr (p
, '/');
1475 len
= 0; /* loop may not be entered, e.g., for "/" */
1480 strncat (temp
, p
, q
- p
);
1481 len
= readlink (temp
, buf
, bufsiz
);
1484 if (strlen (temp
) + 1 > bufsiz
)
1494 if (len
+ strlen (p
) + 1 >= bufsiz
)
1498 return len
+ strlen (p
);
1503 umask (mode_t numask
)
1505 static mode_t mask
= 022;
1506 mode_t oldmask
= mask
;
1513 chmod (const char *path
, mode_t mode
)
1515 /* say it always succeed for now */
1524 return fcntl (oldd
, F_DUPFD
, 0);
1526 /* current implementation of fcntl in fcntl.mac.c simply returns old
1528 return fcntl (oldd
, F_DUPFD
);
1535 /* This is from the original sysdep.c. Emulate BSD dup2. First close
1536 newd if it already exists. Then, attempt to dup oldd. If not
1537 successful, call dup2 recursively until we are, then close the
1538 unsuccessful ones. */
1541 dup2 (int oldd
, int newd
)
1552 ret
= dup2 (oldd
, newd
);
1558 /* let it fail for now */
1575 ioctl (int d
, int request
, void *argp
)
1585 if (fildes
>=0 && fildes
<= 2)
1618 #endif /* __MRC__ */
1622 #if __MSL__ < 0x6000
1630 #endif /* __MWERKS__ */
1632 #endif /* ! MAC_OSX */
1635 /* Return the path to the directory in which Emacs can create
1636 temporary files. The MacOS "temporary items" directory cannot be
1637 used because it removes the file written by a process when it
1638 exits. In that sense it's more like "/dev/null" than "/tmp" (but
1639 again not exactly). And of course Emacs needs to read back the
1640 files written by its subprocesses. So here we write the files to a
1641 directory "Emacs" in the Preferences Folder. This directory is
1642 created if it does not exist. */
1645 get_temp_dir_name ()
1647 static char *temp_dir_name
= NULL
;
1651 Str255 dir_name
, full_path
;
1653 char unix_dir_name
[MAXPATHLEN
+1];
1656 /* Cache directory name with pointer temp_dir_name.
1657 Look for it only the first time. */
1660 err
= FindFolder (kOnSystemDisk
, kPreferencesFolderType
, kCreateFolder
,
1661 &vol_ref_num
, &dir_id
);
1665 if (!path_from_vol_dir_name (full_path
, 255, vol_ref_num
, dir_id
, "\p"))
1668 if (strlen (full_path
) + 6 <= MAXPATHLEN
)
1669 strcat (full_path
, "Emacs:");
1673 if (!mac_to_posix_pathname (full_path
, unix_dir_name
, MAXPATHLEN
+1))
1676 dir
= opendir (unix_dir_name
); /* check whether temp directory exists */
1679 else if (mkdir (unix_dir_name
, 0700) != 0) /* create it if not */
1682 temp_dir_name
= (char *) malloc (strlen (unix_dir_name
) + 1);
1683 strcpy (temp_dir_name
, unix_dir_name
);
1686 return temp_dir_name
;
1691 /* Allocate and construct an array of pointers to strings from a list
1692 of strings stored in a 'STR#' resource. The returned pointer array
1693 is stored in the style of argv and environ: if the 'STR#' resource
1694 contains numString strings, an pointer array with numString+1
1695 elements is returned in which the last entry contains a null
1696 pointer. The pointer to the pointer array is passed by pointer in
1697 parameter t. The resource ID of the 'STR#' resource is passed in
1698 parameter StringListID.
1702 get_string_list (char ***t
, short string_list_id
)
1708 h
= GetResource ('STR#', string_list_id
);
1713 num_strings
= * (short *) p
;
1715 *t
= (char **) malloc (sizeof (char *) * (num_strings
+ 1));
1716 for (i
= 0; i
< num_strings
; i
++)
1718 short length
= *p
++;
1719 (*t
)[i
] = (char *) malloc (length
+ 1);
1720 strncpy ((*t
)[i
], p
, length
);
1721 (*t
)[i
][length
] = '\0';
1724 (*t
)[num_strings
] = 0;
1729 /* Return no string in case GetResource fails. Bug fixed by
1730 Ikegami Tsutomu. Caused MPW build to crash without sym -on
1731 option (no sym -on implies -opt local). */
1732 *t
= (char **) malloc (sizeof (char *));
1739 get_path_to_system_folder ()
1744 Str255 dir_name
, full_path
;
1746 static char system_folder_unix_name
[MAXPATHLEN
+1];
1749 err
= FindFolder (kOnSystemDisk
, kSystemFolderType
, kDontCreateFolder
,
1750 &vol_ref_num
, &dir_id
);
1754 if (!path_from_vol_dir_name (full_path
, 255, vol_ref_num
, dir_id
, "\p"))
1757 if (!mac_to_posix_pathname (full_path
, system_folder_unix_name
,
1761 return system_folder_unix_name
;
1767 #define ENVIRON_STRING_LIST_ID 128
1769 /* Get environment variable definitions from STR# resource. */
1776 get_string_list (&environ
, ENVIRON_STRING_LIST_ID
);
1782 /* Make HOME directory the one Emacs starts up in if not specified
1784 if (getenv ("HOME") == NULL
)
1786 environ
= (char **) realloc (environ
, sizeof (char *) * (i
+ 2));
1789 environ
[i
] = (char *) malloc (strlen (my_passwd_dir
) + 6);
1792 strcpy (environ
[i
], "HOME=");
1793 strcat (environ
[i
], my_passwd_dir
);
1800 /* Make HOME directory the one Emacs starts up in if not specified
1802 if (getenv ("MAIL") == NULL
)
1804 environ
= (char **) realloc (environ
, sizeof (char *) * (i
+ 2));
1807 char * path_to_system_folder
= get_path_to_system_folder ();
1808 environ
[i
] = (char *) malloc (strlen (path_to_system_folder
) + 22);
1811 strcpy (environ
[i
], "MAIL=");
1812 strcat (environ
[i
], path_to_system_folder
);
1813 strcat (environ
[i
], "Eudora Folder/In");
1821 /* Return the value of the environment variable NAME. */
1824 getenv (const char *name
)
1826 int length
= strlen(name
);
1829 for (e
= environ
; *e
!= 0; e
++)
1830 if (strncmp(*e
, name
, length
) == 0 && (*e
)[length
] == '=')
1831 return &(*e
)[length
+ 1];
1833 if (strcmp (name
, "TMPDIR") == 0)
1834 return get_temp_dir_name ();
1841 /* see Interfaces&Libraries:Interfaces:CIncludes:signal.h */
1842 char *sys_siglist
[] =
1844 "Zero is not a signal!!!",
1846 "Interactive user interrupt", /* 2 */ "?",
1847 "Floating point exception", /* 4 */ "?", "?", "?",
1848 "Illegal instruction", /* 8 */ "?", "?", "?", "?", "?", "?", "?",
1849 "Segment violation", /* 16 */ "?", "?", "?", "?", "?", "?", "?",
1850 "?", "?", "?", "?", "?", "?", "?", "?",
1854 char *sys_siglist
[] =
1856 "Zero is not a signal!!!",
1858 "Floating point exception",
1859 "Illegal instruction",
1860 "Interactive user interrupt",
1861 "Segment violation",
1864 #else /* not __MRC__ and not __MWERKS__ */
1866 #endif /* not __MRC__ and not __MWERKS__ */
1869 #include <utsname.h>
1872 uname (struct utsname
*name
)
1875 system_name
= GetString (-16413); /* IM - Resource Manager Reference */
1878 BlockMove (*system_name
, name
->nodename
, (*system_name
)[0]+1);
1879 p2cstr (name
->nodename
);
1887 #include <Processes.h>
1890 /* Event class of HLE sent to subprocess. */
1891 const OSType kEmacsSubprocessSend
= 'ESND';
1893 /* Event class of HLE sent back from subprocess. */
1894 const OSType kEmacsSubprocessReply
= 'ERPY';
1898 mystrchr (char *s
, char c
)
1900 while (*s
&& *s
!= c
)
1928 mystrcpy (char *to
, char *from
)
1940 /* Start a Mac subprocess. Arguments for it is passed in argv (null
1941 terminated). The process should run with the default directory
1942 "workdir", read input from "infn", and write output and error to
1943 "outfn" and "errfn", resp. The Process Manager call
1944 LaunchApplication is used to start the subprocess. We use high
1945 level events as the mechanism to pass arguments to the subprocess
1946 and to make Emacs wait for the subprocess to terminate and pass
1947 back a result code. The bulk of the code here packs the arguments
1948 into one message to be passed together with the high level event.
1949 Emacs also sometimes starts a subprocess using a shell to perform
1950 wildcard filename expansion. Since we don't really have a shell on
1951 the Mac, this case is detected and the starting of the shell is
1952 by-passed. We really need to add code here to do filename
1953 expansion to support such functionality. */
1956 run_mac_command (argv
, workdir
, infn
, outfn
, errfn
)
1957 unsigned char **argv
;
1958 const char *workdir
;
1959 const char *infn
, *outfn
, *errfn
;
1961 #ifdef TARGET_API_MAC_CARBON
1963 #else /* not TARGET_API_MAC_CARBON */
1964 char macappname
[MAXPATHLEN
+1], macworkdir
[MAXPATHLEN
+1];
1965 char macinfn
[MAXPATHLEN
+1], macoutfn
[MAXPATHLEN
+1], macerrfn
[MAXPATHLEN
+1];
1966 int paramlen
, argc
, newargc
, j
, retries
;
1967 char **newargv
, *param
, *p
;
1970 LaunchParamBlockRec lpbr
;
1971 EventRecord send_event
, reply_event
;
1972 RgnHandle cursor_region_handle
;
1974 unsigned long ref_con
, len
;
1976 if (posix_to_mac_pathname (workdir
, macworkdir
, MAXPATHLEN
+1) == 0)
1978 if (posix_to_mac_pathname (infn
, macinfn
, MAXPATHLEN
+1) == 0)
1980 if (posix_to_mac_pathname (outfn
, macoutfn
, MAXPATHLEN
+1) == 0)
1982 if (posix_to_mac_pathname (errfn
, macerrfn
, MAXPATHLEN
+1) == 0)
1985 paramlen
= strlen (macworkdir
) + strlen (macinfn
) + strlen (macoutfn
)
1986 + strlen (macerrfn
) + 4; /* count nulls at end of strings */
1995 /* If a subprocess is invoked with a shell, we receive 3 arguments
1996 of the form: "<path to emacs bins>/sh" "-c" "<path to emacs
1997 bins>/<command> <command args>" */
1998 j
= strlen (argv
[0]);
1999 if (j
>= 3 && strcmp (argv
[0]+j
-3, "/sh") == 0
2000 && argc
== 3 && strcmp (argv
[1], "-c") == 0)
2002 char *command
, *t
, tempmacpathname
[MAXPATHLEN
+1];
2004 /* The arguments for the command in argv[2] are separated by
2005 spaces. Count them and put the count in newargc. */
2006 command
= (char *) alloca (strlen (argv
[2])+2);
2007 strcpy (command
, argv
[2]);
2008 if (command
[strlen (command
) - 1] != ' ')
2009 strcat (command
, " ");
2013 t
= mystrchr (t
, ' ');
2017 t
= mystrchr (t
+1, ' ');
2020 newargv
= (char **) alloca (sizeof (char *) * newargc
);
2023 for (j
= 0; j
< newargc
; j
++)
2025 newargv
[j
] = (char *) alloca (strlen (t
) + 1);
2026 mystrcpy (newargv
[j
], t
);
2029 paramlen
+= strlen (newargv
[j
]) + 1;
2032 if (strncmp (newargv
[0], "~emacs/", 7) == 0)
2034 if (posix_to_mac_pathname (newargv
[0], tempmacpathname
, MAXPATHLEN
+1)
2039 { /* sometimes Emacs call "sh" without a path for the command */
2041 char *t
= (char *) alloca (strlen (newargv
[0]) + 7 + 1);
2042 strcpy (t
, "~emacs/");
2043 strcat (t
, newargv
[0]);
2046 openp (Vexec_path
, build_string (newargv
[0]), EXEC_SUFFIXES
, &path
,
2047 make_number (X_OK
));
2051 if (posix_to_mac_pathname (XSTRING (path
)->data
, tempmacpathname
,
2055 strcpy (macappname
, tempmacpathname
);
2059 if (posix_to_mac_pathname (argv
[0], macappname
, MAXPATHLEN
+1) == 0)
2062 newargv
= (char **) alloca (sizeof (char *) * argc
);
2064 for (j
= 1; j
< argc
; j
++)
2066 if (strncmp (argv
[j
], "~emacs/", 7) == 0)
2068 char *t
= strchr (argv
[j
], ' ');
2071 char tempcmdname
[MAXPATHLEN
+1], tempmaccmdname
[MAXPATHLEN
+1];
2072 strncpy (tempcmdname
, argv
[j
], t
-argv
[j
]);
2073 tempcmdname
[t
-argv
[j
]] = '\0';
2074 if (posix_to_mac_pathname (tempcmdname
, tempmaccmdname
,
2077 newargv
[j
] = (char *) alloca (strlen (tempmaccmdname
)
2079 strcpy (newargv
[j
], tempmaccmdname
);
2080 strcat (newargv
[j
], t
);
2084 char tempmaccmdname
[MAXPATHLEN
+1];
2085 if (posix_to_mac_pathname (argv
[j
], tempmaccmdname
,
2088 newargv
[j
] = (char *) alloca (strlen (tempmaccmdname
)+1);
2089 strcpy (newargv
[j
], tempmaccmdname
);
2093 newargv
[j
] = argv
[j
];
2094 paramlen
+= strlen (newargv
[j
]) + 1;
2098 /* After expanding all the arguments, we now know the length of the
2099 parameter block to be sent to the subprocess as a message
2100 attached to the HLE. */
2101 param
= (char *) malloc (paramlen
+ 1);
2107 /* first byte of message contains number of arguments for command */
2108 strcpy (p
, macworkdir
);
2109 p
+= strlen (macworkdir
);
2111 /* null terminate strings sent so it's possible to use strcpy over there */
2112 strcpy (p
, macinfn
);
2113 p
+= strlen (macinfn
);
2115 strcpy (p
, macoutfn
);
2116 p
+= strlen (macoutfn
);
2118 strcpy (p
, macerrfn
);
2119 p
+= strlen (macerrfn
);
2121 for (j
= 1; j
< newargc
; j
++)
2123 strcpy (p
, newargv
[j
]);
2124 p
+= strlen (newargv
[j
]);
2128 c2pstr (macappname
);
2130 iErr
= FSMakeFSSpec (0, 0, macappname
, &spec
);
2138 lpbr
.launchBlockID
= extendedBlock
;
2139 lpbr
.launchEPBLength
= extendedBlockLen
;
2140 lpbr
.launchControlFlags
= launchContinue
+ launchNoFileFlags
;
2141 lpbr
.launchAppSpec
= &spec
;
2142 lpbr
.launchAppParameters
= NULL
;
2144 iErr
= LaunchApplication (&lpbr
); /* call the subprocess */
2151 send_event
.what
= kHighLevelEvent
;
2152 send_event
.message
= kEmacsSubprocessSend
;
2153 /* Event ID stored in "where" unused */
2156 /* OS may think current subprocess has terminated if previous one
2157 terminated recently. */
2160 iErr
= PostHighLevelEvent (&send_event
, &lpbr
.launchProcessSN
, 0, param
,
2161 paramlen
+ 1, receiverIDisPSN
);
2163 while (iErr
== sessClosedErr
&& retries
-- > 0);
2171 cursor_region_handle
= NewRgn ();
2173 /* Wait for the subprocess to finish, when it will send us a ERPY
2174 high level event. */
2176 if (WaitNextEvent (highLevelEventMask
, &reply_event
, 180,
2177 cursor_region_handle
)
2178 && reply_event
.message
== kEmacsSubprocessReply
)
2181 /* The return code is sent through the refCon */
2182 iErr
= AcceptHighLevelEvent (&targ
, &ref_con
, NULL
, &len
);
2185 DisposeHandle ((Handle
) cursor_region_handle
);
2190 DisposeHandle ((Handle
) cursor_region_handle
);
2194 #endif /* not TARGET_API_MAC_CARBON */
2199 opendir (const char *dirname
)
2201 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
2202 char mac_pathname
[MAXPATHLEN
+1], vol_name
[MAXPATHLEN
+1];
2206 int len
, vol_name_len
;
2208 if (find_true_pathname (dirname
, true_pathname
, MAXPATHLEN
+1) == -1)
2211 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
2213 fully_resolved_name
[len
] = '\0';
2215 strcpy (fully_resolved_name
, true_pathname
);
2217 dirp
= (DIR *) malloc (sizeof(DIR));
2221 /* Handle special case when dirname is "/": sets up for readir to
2222 get all mount volumes. */
2223 if (strcmp (fully_resolved_name
, "/") == 0)
2225 dirp
->getting_volumes
= 1; /* special all mounted volumes DIR struct */
2226 dirp
->current_index
= 1; /* index for first volume */
2230 /* Handle typical cases: not accessing all mounted volumes. */
2231 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
2234 /* Emacs calls opendir without the trailing '/', Mac needs trailing ':' */
2235 len
= strlen (mac_pathname
);
2236 if (mac_pathname
[len
- 1] != ':' && len
< MAXPATHLEN
)
2237 strcat (mac_pathname
, ":");
2239 /* Extract volume name */
2240 vol_name_len
= strchr (mac_pathname
, ':') - mac_pathname
;
2241 strncpy (vol_name
, mac_pathname
, vol_name_len
);
2242 vol_name
[vol_name_len
] = '\0';
2243 strcat (vol_name
, ":");
2245 c2pstr (mac_pathname
);
2246 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
2247 /* using full pathname so vRefNum and DirID ignored */
2248 cipb
.hFileInfo
.ioVRefNum
= 0;
2249 cipb
.hFileInfo
.ioDirID
= 0;
2250 cipb
.hFileInfo
.ioFDirIndex
= 0;
2251 /* set to 0 to get information about specific dir or file */
2253 errno
= PBGetCatInfo (&cipb
, false);
2260 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x10)) /* bit 4 = 1 for directories */
2261 return 0; /* not a directory */
2263 dirp
->dir_id
= cipb
.dirInfo
.ioDrDirID
; /* used later in readdir */
2264 dirp
->getting_volumes
= 0;
2265 dirp
->current_index
= 1; /* index for first file/directory */
2268 vpb
.ioNamePtr
= vol_name
;
2269 /* using full pathname so vRefNum and DirID ignored */
2271 vpb
.ioVolIndex
= -1;
2272 errno
= PBHGetVInfo ((union HParamBlockRec
*) &vpb
, false);
2279 dirp
->vol_ref_num
= vpb
.ioVRefNum
;
2296 HParamBlockRec hpblock
;
2298 static struct dirent s_dirent
;
2299 static Str255 s_name
;
2303 /* Handle the root directory containing the mounted volumes. Call
2304 PBHGetVInfo specifying an index to obtain the info for a volume.
2305 PBHGetVInfo returns an error when it receives an index beyond the
2306 last volume, at which time we should return a nil dirent struct
2308 if (dp
->getting_volumes
)
2310 hpblock
.volumeParam
.ioNamePtr
= s_name
;
2311 hpblock
.volumeParam
.ioVRefNum
= 0;
2312 hpblock
.volumeParam
.ioVolIndex
= dp
->current_index
;
2314 errno
= PBHGetVInfo (&hpblock
, false);
2322 strcat (s_name
, "/"); /* need "/" for stat to work correctly */
2324 dp
->current_index
++;
2326 s_dirent
.d_ino
= hpblock
.volumeParam
.ioVRefNum
;
2327 s_dirent
.d_name
= s_name
;
2333 cipb
.hFileInfo
.ioVRefNum
= dp
->vol_ref_num
;
2334 cipb
.hFileInfo
.ioNamePtr
= s_name
;
2335 /* location to receive filename returned */
2337 /* return only visible files */
2341 cipb
.hFileInfo
.ioDirID
= dp
->dir_id
;
2342 /* directory ID found by opendir */
2343 cipb
.hFileInfo
.ioFDirIndex
= dp
->current_index
;
2345 errno
= PBGetCatInfo (&cipb
, false);
2352 /* insist on an visibile entry */
2353 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* directory? */
2354 done
= !(cipb
.dirInfo
.ioDrUsrWds
.frFlags
& fInvisible
);
2356 done
= !(cipb
.hFileInfo
.ioFlFndrInfo
.fdFlags
& fInvisible
);
2358 dp
->current_index
++;
2371 s_dirent
.d_ino
= cipb
.dirInfo
.ioDrDirID
;
2372 /* value unimportant: non-zero for valid file */
2373 s_dirent
.d_name
= s_name
;
2383 char mac_pathname
[MAXPATHLEN
+1];
2384 Str255 directory_name
;
2388 if (path_from_vol_dir_name (mac_pathname
, 255, 0, 0, "\p") == 0)
2391 if (mac_to_posix_pathname (mac_pathname
, path
, MAXPATHLEN
+1) == 0)
2397 #endif /* ! MAC_OSX */
2401 initialize_applescript ()
2406 /* if open fails, as_scripting_component is set to NULL. Its
2407 subsequent use in OSA calls will fail with badComponentInstance
2409 as_scripting_component
= OpenDefaultComponent (kOSAComponentType
,
2410 kAppleScriptSubtype
);
2412 null_desc
.descriptorType
= typeNull
;
2413 null_desc
.dataHandle
= 0;
2414 osaerror
= OSAMakeContext (as_scripting_component
, &null_desc
,
2415 kOSANullScript
, &as_script_context
);
2417 as_script_context
= kOSANullScript
;
2418 /* use default context if create fails */
2422 void terminate_applescript()
2424 OSADispose (as_scripting_component
, as_script_context
);
2425 CloseComponent (as_scripting_component
);
2429 /* Compile and execute the AppleScript SCRIPT and return the error
2430 status as function value. A zero is returned if compilation and
2431 execution is successful, in which case RESULT returns a pointer to
2432 a string containing the resulting script value. Otherwise, the Mac
2433 error code is returned and RESULT returns a pointer to an error
2434 string. In both cases the caller should deallocate the storage
2435 used by the string pointed to by RESULT if it is non-NULL. For
2436 documentation on the MacOS scripting architecture, see Inside
2437 Macintosh - Interapplication Communications: Scripting Components. */
2440 do_applescript (char *script
, char **result
)
2442 AEDesc script_desc
, result_desc
, error_desc
;
2449 if (!as_scripting_component
)
2450 initialize_applescript();
2452 error
= AECreateDesc (typeChar
, script
, strlen(script
), &script_desc
);
2456 osaerror
= OSADoScript (as_scripting_component
, &script_desc
, kOSANullScript
,
2457 typeChar
, kOSAModeNull
, &result_desc
);
2459 if (osaerror
== errOSAScriptError
)
2461 /* error executing AppleScript: retrieve error message */
2462 if (!OSAScriptError (as_scripting_component
, kOSAErrorMessage
, typeChar
,
2465 #if TARGET_API_MAC_CARBON
2466 length
= AEGetDescDataSize (&error_desc
);
2467 *result
= (char *) xmalloc (length
+ 1);
2470 AEGetDescData (&error_desc
, *result
, length
);
2471 *(*result
+ length
) = '\0';
2473 #else /* not TARGET_API_MAC_CARBON */
2474 HLock (error_desc
.dataHandle
);
2475 length
= GetHandleSize(error_desc
.dataHandle
);
2476 *result
= (char *) xmalloc (length
+ 1);
2479 memcpy (*result
, *(error_desc
.dataHandle
), length
);
2480 *(*result
+ length
) = '\0';
2482 HUnlock (error_desc
.dataHandle
);
2483 #endif /* not TARGET_API_MAC_CARBON */
2484 AEDisposeDesc (&error_desc
);
2487 else if (osaerror
== noErr
) /* success: retrieve resulting script value */
2489 #if TARGET_API_MAC_CARBON
2490 length
= AEGetDescDataSize (&result_desc
);
2491 *result
= (char *) xmalloc (length
+ 1);
2494 AEGetDescData (&result_desc
, *result
, length
);
2495 *(*result
+ length
) = '\0';
2497 #else /* not TARGET_API_MAC_CARBON */
2498 HLock (result_desc
.dataHandle
);
2499 length
= GetHandleSize(result_desc
.dataHandle
);
2500 *result
= (char *) xmalloc (length
+ 1);
2503 memcpy (*result
, *(result_desc
.dataHandle
), length
);
2504 *(*result
+ length
) = '\0';
2506 HUnlock (result_desc
.dataHandle
);
2507 #endif /* not TARGET_API_MAC_CARBON */
2508 AEDisposeDesc (&result_desc
);
2511 AEDisposeDesc (&script_desc
);
2517 DEFUN ("do-applescript", Fdo_applescript
, Sdo_applescript
, 1, 1, 0,
2518 doc
: /* Compile and execute AppleScript SCRIPT and retrieve and return the result.
2519 If compilation and execution are successful, the resulting script
2520 value is returned as a string. Otherwise the function aborts and
2521 displays the error message returned by the AppleScript scripting
2526 char *result
, *temp
;
2527 Lisp_Object lisp_result
;
2530 CHECK_STRING (script
);
2532 status
= do_applescript (XSTRING (script
)->data
, &result
);
2536 error ("AppleScript error %d", status
);
2539 /* Unfortunately only OSADoScript in do_applescript knows how
2540 how large the resulting script value or error message is
2541 going to be and therefore as caller memory must be
2542 deallocated here. It is necessary to free the error
2543 message before calling error to avoid a memory leak. */
2544 temp
= (char *) alloca (strlen (result
) + 1);
2545 strcpy (temp
, result
);
2552 lisp_result
= build_string (result
);
2559 DEFUN ("mac-file-name-to-posix", Fmac_file_name_to_posix
,
2560 Smac_file_name_to_posix
, 1, 1, 0,
2561 doc
: /* Convert Macintosh filename to Posix form. */)
2563 Lisp_Object mac_filename
;
2565 char posix_filename
[MAXPATHLEN
+1];
2567 CHECK_STRING (mac_filename
);
2569 if (mac_to_posix_pathname (XSTRING (mac_filename
)->data
, posix_filename
,
2571 return build_string (posix_filename
);
2577 DEFUN ("posix-file-name-to-mac", Fposix_file_name_to_mac
,
2578 Sposix_file_name_to_mac
, 1, 1, 0,
2579 doc
: /* Convert Posix filename to Mac form. */)
2581 Lisp_Object posix_filename
;
2583 char mac_filename
[MAXPATHLEN
+1];
2585 CHECK_STRING (posix_filename
);
2587 if (posix_to_mac_pathname (XSTRING (posix_filename
)->data
, mac_filename
,
2589 return build_string (mac_filename
);
2595 /* set interprogram-paste-function to mac-paste-function in mac-win.el
2596 to enable Emacs to obtain the contents of the Mac clipboard. */
2597 DEFUN ("mac-paste-function", Fmac_paste_function
, Smac_paste_function
, 0, 0, 0,
2598 doc
: /* Return the contents of the Mac clipboard as a string. */)
2601 #if TARGET_API_MAC_CARBON
2603 ScrapFlavorFlags sff
;
2608 if (GetCurrentScrap (&scrap
) != noErr
)
2611 if (GetScrapFlavorFlags (scrap
, kScrapFlavorTypeText
, &sff
) != noErr
)
2614 if (GetScrapFlavorSize (scrap
, kScrapFlavorTypeText
, &s
) != noErr
)
2617 if ((data
= (char*) alloca (s
)) == NULL
)
2620 if (GetScrapFlavorData (scrap
, kScrapFlavorTypeText
, &s
, data
) != noErr
2624 /* Emacs expects clipboard contents have Unix-style eol's */
2625 for (i
= 0; i
< s
; i
++)
2626 if (data
[i
] == '\r')
2629 return make_string (data
, s
);
2630 #else /* not TARGET_API_MAC_CARBON */
2633 long scrap_offset
, rc
, i
;
2635 my_handle
= NewHandle (0); /* allocate 0-length data area */
2637 rc
= GetScrap (my_handle
, 'TEXT', &scrap_offset
);
2643 /* Emacs expects clipboard contents have Unix-style eol's */
2644 for (i
= 0; i
< rc
; i
++)
2645 if ((*my_handle
)[i
] == '\r')
2646 (*my_handle
)[i
] = '\n';
2648 value
= make_string (*my_handle
, rc
);
2650 HUnlock (my_handle
);
2652 DisposeHandle (my_handle
);
2655 #endif /* not TARGET_API_MAC_CARBON */
2659 /* set interprogram-cut-function to mac-cut-function in mac-win.el
2660 to enable Emacs to write the top of the kill-ring to the Mac clipboard. */
2661 DEFUN ("mac-cut-function", Fmac_cut_function
, Smac_cut_function
, 1, 2, 0,
2662 doc
: /* Put the value of the string parameter to the Mac clipboard. */)
2664 Lisp_Object value
, push
;
2669 /* fixme: ignore the push flag for now */
2671 CHECK_STRING (value
);
2673 len
= XSTRING (value
)->size
;
2674 buf
= (char *) alloca (len
+1);
2675 bcopy (XSTRING (value
)->data
, buf
, len
);
2678 /* convert to Mac-style eol's before sending to clipboard */
2679 for (i
= 0; i
< len
; i
++)
2683 #if TARGET_API_MAC_CARBON
2686 ClearCurrentScrap ();
2687 if (GetCurrentScrap (&scrap
) != noErr
)
2688 error ("cannot get current scrap");
2690 if (PutScrapFlavor (scrap
, kScrapFlavorTypeText
, kScrapFlavorMaskNone
, len
,
2692 error ("cannot put to scrap");
2694 #else /* not TARGET_API_MAC_CARBON */
2696 PutScrap (len
, 'TEXT', buf
);
2697 #endif /* not TARGET_API_MAC_CARBON */
2703 DEFUN ("x-selection-exists-p", Fx_selection_exists_p
, Sx_selection_exists_p
,
2705 doc
: /* Whether there is an owner for the given X Selection.
2706 The arg should be the name of the selection in question, typically one of
2707 the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.
2708 \(Those are literal upper-case symbol names, since that's what X expects.)
2709 For convenience, the symbol nil is the same as `PRIMARY',
2710 and t is the same as `SECONDARY'. */)
2712 Lisp_Object selection
;
2714 CHECK_SYMBOL (selection
);
2716 /* Return nil for PRIMARY and SECONDARY selections; for CLIPBOARD, check
2717 if the clipboard currently has valid text format contents. */
2719 if (EQ (selection
, QCLIPBOARD
))
2721 Lisp_Object val
= Qnil
;
2723 #if TARGET_API_MAC_CARBON
2725 ScrapFlavorFlags sff
;
2727 if (GetCurrentScrap (&scrap
) == noErr
)
2728 if (GetScrapFlavorFlags (scrap
, kScrapFlavorTypeText
, &sff
) == noErr
)
2730 #else /* not TARGET_API_MAC_CARBON */
2732 long rc
, scrap_offset
;
2734 my_handle
= NewHandle (0);
2736 rc
= GetScrap (my_handle
, 'TEXT', &scrap_offset
);
2740 DisposeHandle (my_handle
);
2741 #endif /* not TARGET_API_MAC_CARBON */
2752 QCLIPBOARD
= intern ("CLIPBOARD");
2753 staticpro (&QCLIPBOARD
);
2755 defsubr (&Smac_paste_function
);
2756 defsubr (&Smac_cut_function
);
2758 defsubr (&Sx_selection_exists_p
);
2761 defsubr (&Sdo_applescript
);
2762 defsubr (&Smac_file_name_to_posix
);
2763 defsubr (&Sposix_file_name_to_mac
);