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>
43 #include <Carbon/Carbon.h>
45 #define free unexec_free
47 #define malloc unexec_malloc
49 #define realloc unexec_realloc
50 #else /* not MAC_OSX */
53 #include <TextUtils.h>
55 #include <Resources.h>
60 #include <AppleScript.h>
62 #endif /* not MAC_OSX */
66 #include "sysselect.h"
69 Lisp_Object QCLIPBOARD
;
71 /* An instance of the AppleScript component. */
72 static ComponentInstance as_scripting_component
;
73 /* The single script context used for all script executions. */
74 static OSAID as_script_context
;
77 /* When converting from Mac to Unix pathnames, /'s in folder names are
78 converted to :'s. This function, used in copying folder names,
79 performs a strncat and converts all character a to b in the copy of
80 the string s2 appended to the end of s1. */
83 string_cat_and_replace (char *s1
, const char *s2
, int n
, char a
, char b
)
91 for (i
= 0; i
< l2
; i
++)
100 /* Convert a Mac pathname to Posix form. A Mac full pathname is one
101 that does not begin with a ':' and contains at least one ':'. A Mac
102 full pathname causes an '/' to be prepended to the Posix pathname.
103 The algorithm for the rest of the pathname is as follows:
104 For each segment between two ':',
105 if it is non-null, copy as is and then add a '/' at the end,
106 otherwise, insert a "../" into the Posix pathname.
107 Returns 1 if successful; 0 if fails. */
110 mac_to_posix_pathname (const char *mfn
, char *ufn
, int ufnbuflen
)
112 const char *p
, *q
, *pe
;
119 p
= strchr (mfn
, ':');
120 if (p
!= 0 && p
!= mfn
) /* full pathname */
127 pe
= mfn
+ strlen (mfn
);
134 { /* two consecutive ':' */
135 if (strlen (ufn
) + 3 >= ufnbuflen
)
141 if (strlen (ufn
) + (q
- p
) + 1 >= ufnbuflen
)
143 string_cat_and_replace (ufn
, p
, q
- p
, '/', ':');
150 if (strlen (ufn
) + (pe
- p
) >= ufnbuflen
)
152 string_cat_and_replace (ufn
, p
, pe
- p
, '/', ':');
153 /* no separator for last one */
162 extern char *get_temp_dir_name ();
165 /* Convert a Posix pathname to Mac form. Approximately reverse of the
166 above in algorithm. */
169 posix_to_mac_pathname (const char *ufn
, char *mfn
, int mfnbuflen
)
171 const char *p
, *q
, *pe
;
172 char expanded_pathname
[MAXPATHLEN
+1];
181 /* Check for and handle volume names. Last comparison: strangely
182 somewhere "/.emacs" is passed. A temporary fix for now. */
183 if (*p
== '/' && strchr (p
+1, '/') == NULL
&& strcmp (p
, "/.emacs") != 0)
185 if (strlen (p
) + 1 > mfnbuflen
)
192 /* expand to emacs dir found by init_emacs_passwd_dir */
193 if (strncmp (p
, "~emacs/", 7) == 0)
195 struct passwd
*pw
= getpwnam ("emacs");
197 if (strlen (pw
->pw_dir
) + strlen (p
) > MAXPATHLEN
)
199 strcpy (expanded_pathname
, pw
->pw_dir
);
200 strcat (expanded_pathname
, p
);
201 p
= expanded_pathname
;
202 /* now p points to the pathname with emacs dir prefix */
204 else if (strncmp (p
, "/tmp/", 5) == 0)
206 char *t
= get_temp_dir_name ();
208 if (strlen (t
) + strlen (p
) > MAXPATHLEN
)
210 strcpy (expanded_pathname
, t
);
211 strcat (expanded_pathname
, p
);
212 p
= expanded_pathname
;
213 /* now p points to the pathname with emacs dir prefix */
215 else if (*p
!= '/') /* relative pathname */
227 if (q
- p
== 2 && *p
== '.' && *(p
+1) == '.')
229 if (strlen (mfn
) + 1 >= mfnbuflen
)
235 if (strlen (mfn
) + (q
- p
) + 1 >= mfnbuflen
)
237 string_cat_and_replace (mfn
, p
, q
- p
, ':', '/');
244 if (strlen (mfn
) + (pe
- p
) >= mfnbuflen
)
246 string_cat_and_replace (mfn
, p
, pe
- p
, ':', '/');
256 /* The following functions with "sys_" prefix are stubs to Unix
257 functions that have already been implemented by CW or MPW. The
258 calls to them in Emacs source course are #define'd to call the sys_
259 versions by the header files s-mac.h. In these stubs pathnames are
260 converted between their Unix and Mac forms. */
263 /* Unix epoch is Jan 1, 1970 while Mac epoch is Jan 1, 1904: 66 years
264 + 17 leap days. These are for adjusting time values returned by
265 MacOS Toolbox functions. */
267 #define MAC_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
271 /* CW Pro 5 epoch is Jan 1, 1900 (aaarghhhhh!); remember, 1900 is not
272 a leap year! This is for adjusting time_t values returned by MSL
274 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 70 + 17) * 24 * 60 * 60)
275 #else /* __MSL__ >= 0x6000 */
276 /* CW changes Pro 6 to follow Unix! */
277 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
278 #endif /* __MSL__ >= 0x6000 */
280 /* MPW library functions follow Unix (confused?). */
281 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
282 #else /* not __MRC__ */
284 #endif /* not __MRC__ */
287 /* Define our own stat function for both MrC and CW. The reason for
288 doing this: "stat" is both the name of a struct and function name:
289 can't use the same trick like that for sys_open, sys_close, etc. to
290 redirect Emacs's calls to our own version that converts Unix style
291 filenames to Mac style filename because all sorts of compilation
292 errors will be generated if stat is #define'd to be sys_stat. */
295 stat_noalias (const char *path
, struct stat
*buf
)
297 char mac_pathname
[MAXPATHLEN
+1];
300 if (posix_to_mac_pathname (path
, mac_pathname
, MAXPATHLEN
+1) == 0)
303 c2pstr (mac_pathname
);
304 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
305 cipb
.hFileInfo
.ioVRefNum
= 0;
306 cipb
.hFileInfo
.ioDirID
= 0;
307 cipb
.hFileInfo
.ioFDirIndex
= 0;
308 /* set to 0 to get information about specific dir or file */
310 errno
= PBGetCatInfo (&cipb
, false);
311 if (errno
== -43) /* -43: fnfErr defined in Errors.h */
316 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* bit 4 = 1 for directories */
318 buf
->st_mode
= S_IFDIR
| S_IREAD
| S_IEXEC
;
320 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x1))
321 buf
->st_mode
|= S_IWRITE
; /* bit 1 = 1 for locked files/directories */
322 buf
->st_ino
= cipb
.dirInfo
.ioDrDirID
;
323 buf
->st_dev
= cipb
.dirInfo
.ioVRefNum
;
324 buf
->st_size
= cipb
.dirInfo
.ioDrNmFls
;
325 /* size of dir = number of files and dirs */
328 = cipb
.dirInfo
.ioDrMdDat
- MAC_UNIX_EPOCH_DIFF
;
329 buf
->st_ctime
= cipb
.dirInfo
.ioDrCrDat
- MAC_UNIX_EPOCH_DIFF
;
333 buf
->st_mode
= S_IFREG
| S_IREAD
;
334 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x1))
335 buf
->st_mode
|= S_IWRITE
; /* bit 1 = 1 for locked files/directories */
336 if (cipb
.hFileInfo
.ioFlFndrInfo
.fdType
== 'APPL')
337 buf
->st_mode
|= S_IEXEC
;
338 buf
->st_ino
= cipb
.hFileInfo
.ioDirID
;
339 buf
->st_dev
= cipb
.hFileInfo
.ioVRefNum
;
340 buf
->st_size
= cipb
.hFileInfo
.ioFlLgLen
;
343 = cipb
.hFileInfo
.ioFlMdDat
- MAC_UNIX_EPOCH_DIFF
;
344 buf
->st_ctime
= cipb
.hFileInfo
.ioFlCrDat
- MAC_UNIX_EPOCH_DIFF
;
347 if (cipb
.hFileInfo
.ioFlFndrInfo
.fdFlags
& 0x8000)
349 /* identify alias files as symlinks */
350 buf
->st_mode
&= ~S_IFREG
;
351 buf
->st_mode
|= S_IFLNK
;
355 buf
->st_uid
= getuid ();
356 buf
->st_gid
= getgid ();
364 lstat (const char *path
, struct stat
*buf
)
367 char true_pathname
[MAXPATHLEN
+1];
369 /* Try looking for the file without resolving aliases first. */
370 if ((result
= stat_noalias (path
, buf
)) >= 0)
373 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
376 return stat_noalias (true_pathname
, buf
);
381 stat (const char *path
, struct stat
*sb
)
384 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
387 if ((result
= stat_noalias (path
, sb
)) >= 0 &&
388 ! (sb
->st_mode
& S_IFLNK
))
391 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
394 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
397 fully_resolved_name
[len
] = '\0';
398 /* in fact our readlink terminates strings */
399 return lstat (fully_resolved_name
, sb
);
402 return lstat (true_pathname
, sb
);
407 /* CW defines fstat in stat.mac.c while MPW does not provide this
408 function. Without the information of how to get from a file
409 descriptor in MPW StdCLib to a Mac OS file spec, it should be hard
410 to implement this function. Fortunately, there is only one place
411 where this function is called in our configuration: in fileio.c,
412 where only the st_dev and st_ino fields are used to determine
413 whether two fildes point to different i-nodes to prevent copying
414 a file onto itself equal. What we have here probably needs
418 fstat (int fildes
, struct stat
*buf
)
421 buf
->st_ino
= fildes
;
422 buf
->st_mode
= S_IFREG
; /* added by T.I. for the copy-file */
423 return 0; /* success */
429 mkdir (const char *dirname
, int mode
)
434 char true_pathname
[MAXPATHLEN
+1], mac_pathname
[MAXPATHLEN
+1];
436 if (find_true_pathname (dirname
, true_pathname
, MAXPATHLEN
+1) == -1)
439 if (posix_to_mac_pathname (true_pathname
, mac_pathname
, MAXPATHLEN
+1) == 0)
442 c2pstr (mac_pathname
);
443 hfpb
.ioNamePtr
= mac_pathname
;
444 hfpb
.ioVRefNum
= 0; /* ignored unless name is invalid */
445 hfpb
.ioDirID
= 0; /* parent is the root */
447 errno
= PBDirCreate ((HParmBlkPtr
) &hfpb
, false);
448 /* just return the Mac OSErr code for now */
449 return errno
== noErr
? 0 : -1;
454 sys_rmdir (const char *dirname
)
457 char mac_pathname
[MAXPATHLEN
+1];
459 if (posix_to_mac_pathname (dirname
, mac_pathname
, MAXPATHLEN
+1) == 0)
462 c2pstr (mac_pathname
);
463 hfpb
.ioNamePtr
= mac_pathname
;
464 hfpb
.ioVRefNum
= 0; /* ignored unless name is invalid */
465 hfpb
.ioDirID
= 0; /* parent is the root */
467 errno
= PBHDelete ((HParmBlkPtr
) &hfpb
, false);
468 return errno
== noErr
? 0 : -1;
473 /* No implementation yet. */
475 execvp (const char *path
, ...)
483 utime (const char *path
, const struct utimbuf
*times
)
485 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
487 char mac_pathname
[MAXPATHLEN
+1];
490 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
493 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
495 fully_resolved_name
[len
] = '\0';
497 strcpy (fully_resolved_name
, true_pathname
);
499 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
502 c2pstr (mac_pathname
);
503 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
504 cipb
.hFileInfo
.ioVRefNum
= 0;
505 cipb
.hFileInfo
.ioDirID
= 0;
506 cipb
.hFileInfo
.ioFDirIndex
= 0;
507 /* set to 0 to get information about specific dir or file */
509 errno
= PBGetCatInfo (&cipb
, false);
513 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* bit 4 = 1 for directories */
516 cipb
.dirInfo
.ioDrMdDat
= times
->modtime
+ MAC_UNIX_EPOCH_DIFF
;
518 GetDateTime (&cipb
.dirInfo
.ioDrMdDat
);
523 cipb
.hFileInfo
.ioFlMdDat
= times
->modtime
+ MAC_UNIX_EPOCH_DIFF
;
525 GetDateTime (&cipb
.hFileInfo
.ioFlMdDat
);
528 errno
= PBSetCatInfo (&cipb
, false);
529 return errno
== noErr
? 0 : -1;
543 /* Like stat, but test for access mode in hfpb.ioFlAttrib */
545 access (const char *path
, int mode
)
547 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
549 char mac_pathname
[MAXPATHLEN
+1];
552 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
555 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
557 fully_resolved_name
[len
] = '\0';
559 strcpy (fully_resolved_name
, true_pathname
);
561 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
564 c2pstr (mac_pathname
);
565 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
566 cipb
.hFileInfo
.ioVRefNum
= 0;
567 cipb
.hFileInfo
.ioDirID
= 0;
568 cipb
.hFileInfo
.ioFDirIndex
= 0;
569 /* set to 0 to get information about specific dir or file */
571 errno
= PBGetCatInfo (&cipb
, false);
575 if (mode
== F_OK
) /* got this far, file exists */
579 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* path refers to a directory */
583 if (cipb
.hFileInfo
.ioFlFndrInfo
.fdType
== 'APPL')
590 return (cipb
.hFileInfo
.ioFlAttrib
& 0x1) ? -1 : 0;
591 /* don't allow if lock bit is on */
597 #define DEV_NULL_FD 0x10000
601 sys_open (const char *path
, int oflag
)
603 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
605 char mac_pathname
[MAXPATHLEN
+1];
607 if (strcmp (path
, "/dev/null") == 0)
608 return DEV_NULL_FD
; /* some bogus fd to be ignored in write */
610 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
613 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
615 fully_resolved_name
[len
] = '\0';
617 strcpy (fully_resolved_name
, true_pathname
);
619 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
624 int res
= open (mac_pathname
, oflag
);
625 /* if (oflag == O_WRONLY || oflag == O_RDWR) */
627 fsetfileinfo (mac_pathname
, 'EMAx', 'TEXT');
629 #else /* not __MRC__ */
630 return open (mac_pathname
, oflag
);
631 #endif /* not __MRC__ */
638 sys_creat (const char *path
, mode_t mode
)
640 char true_pathname
[MAXPATHLEN
+1];
642 char mac_pathname
[MAXPATHLEN
+1];
644 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
647 if (!posix_to_mac_pathname (true_pathname
, mac_pathname
, MAXPATHLEN
+1))
652 int result
= creat (mac_pathname
);
653 fsetfileinfo (mac_pathname
, 'EMAx', 'TEXT');
655 #else /* not __MRC__ */
656 return creat (mac_pathname
, mode
);
657 #endif /* not __MRC__ */
664 sys_unlink (const char *path
)
666 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
668 char mac_pathname
[MAXPATHLEN
+1];
670 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
673 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
675 fully_resolved_name
[len
] = '\0';
677 strcpy (fully_resolved_name
, true_pathname
);
679 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
682 return unlink (mac_pathname
);
688 sys_read (int fildes
, char *buf
, int count
)
690 if (fildes
== 0) /* this should not be used for console input */
693 #if __MSL__ >= 0x6000
694 return _read (fildes
, buf
, count
);
696 return read (fildes
, buf
, count
);
703 sys_write (int fildes
, const char *buf
, int count
)
705 if (fildes
== DEV_NULL_FD
)
708 #if __MSL__ >= 0x6000
709 return _write (fildes
, buf
, count
);
711 return write (fildes
, buf
, count
);
718 sys_rename (const char * old_name
, const char * new_name
)
720 char true_old_pathname
[MAXPATHLEN
+1], true_new_pathname
[MAXPATHLEN
+1];
721 char fully_resolved_old_name
[MAXPATHLEN
+1];
723 char mac_old_name
[MAXPATHLEN
+1], mac_new_name
[MAXPATHLEN
+1];
725 if (find_true_pathname (old_name
, true_old_pathname
, MAXPATHLEN
+1) == -1)
728 len
= readlink (true_old_pathname
, fully_resolved_old_name
, MAXPATHLEN
);
730 fully_resolved_old_name
[len
] = '\0';
732 strcpy (fully_resolved_old_name
, true_old_pathname
);
734 if (find_true_pathname (new_name
, true_new_pathname
, MAXPATHLEN
+1) == -1)
737 if (strcmp (fully_resolved_old_name
, true_new_pathname
) == 0)
740 if (!posix_to_mac_pathname (fully_resolved_old_name
,
745 if (!posix_to_mac_pathname(true_new_pathname
, mac_new_name
, MAXPATHLEN
+1))
748 /* If a file with new_name already exists, rename deletes the old
749 file in Unix. CW version fails in these situation. So we add a
750 call to unlink here. */
751 (void) unlink (mac_new_name
);
753 return rename (mac_old_name
, mac_new_name
);
758 extern FILE *fopen (const char *name
, const char *mode
);
760 sys_fopen (const char *name
, const char *mode
)
762 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
764 char mac_pathname
[MAXPATHLEN
+1];
766 if (find_true_pathname (name
, true_pathname
, MAXPATHLEN
+1) == -1)
769 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
771 fully_resolved_name
[len
] = '\0';
773 strcpy (fully_resolved_name
, true_pathname
);
775 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
780 if (mode
[0] == 'w' || mode
[0] == 'a')
781 fsetfileinfo (mac_pathname
, 'EMAx', 'TEXT');
782 #endif /* not __MRC__ */
783 return fopen (mac_pathname
, mode
);
790 long target_ticks
= 0;
793 __sigfun alarm_signal_func
= (__sigfun
) 0;
795 __signal_func_ptr alarm_signal_func
= (__signal_func_ptr
) 0;
796 #else /* not __MRC__ and not __MWERKS__ */
798 #endif /* not __MRC__ and not __MWERKS__ */
801 /* These functions simulate SIG_ALRM. The stub for function signal
802 stores the signal handler function in alarm_signal_func if a
803 SIG_ALRM is encountered. check_alarm is called in XTread_socket,
804 which emacs calls periodically. A pending alarm is represented by
805 a non-zero target_ticks value. check_alarm calls the handler
806 function pointed to by alarm_signal_func if one has been set up and
807 an alarm is pending. */
812 if (target_ticks
&& TickCount () > target_ticks
)
815 if (alarm_signal_func
)
816 (*alarm_signal_func
)(SIGALRM
);
822 select (n
, rfds
, wfds
, efds
, timeout
)
827 struct timeval
*timeout
;
829 #ifdef TARGET_API_MAC_CARBON
831 #else /* not TARGET_API_MAC_CARBON */
832 EMACS_TIME end_time
, now
;
835 /* Can only handle wait for keyboard input. */
836 if (n
> 1 || wfds
|| efds
)
839 EMACS_GET_TIME (end_time
);
840 EMACS_ADD_TIME (end_time
, end_time
, *timeout
);
844 /* Also return true if an event other than a keyDown has
845 occurred. This causes kbd_buffer_get_event in keyboard.c to
846 call read_avail_input which in turn calls XTread_socket to
847 poll for these events. Otherwise these never get processed
848 except but a very slow poll timer. */
849 if (FD_ISSET (0, rfds
) && EventAvail (everyEvent
, &e
))
852 /* Also check movement of the mouse. */
855 static Point old_mouse_pos
= {-1, -1};
857 GetMouse (&mouse_pos
);
858 if (!EqualPt (mouse_pos
, old_mouse_pos
))
860 old_mouse_pos
= mouse_pos
;
865 WaitNextEvent (0, &e
, 1UL, NULL
); /* Accept no event; wait 1
868 EMACS_GET_TIME (now
);
869 EMACS_SUB_TIME (now
, end_time
, now
);
871 while (!EMACS_TIME_NEG_P (now
));
874 #endif /* not TARGET_API_MAC_CARBON */
878 /* Called in sys_select to wait for an alarm signal to arrive. */
886 if (!target_ticks
) /* no alarm pending */
889 if ((tick
= TickCount ()) < target_ticks
)
890 WaitNextEvent (0, &e
, target_ticks
- tick
, NULL
); /* Accept no event;
891 just wait. by T.I. */
894 if (alarm_signal_func
)
895 (*alarm_signal_func
)(SIGALRM
);
904 long remaining
= target_ticks
? (TickCount () - target_ticks
) / 60 : 0;
906 target_ticks
= seconds
? TickCount () + 60 * seconds
: 0;
908 return (remaining
< 0) ? 0 : (unsigned int) remaining
;
914 extern __sigfun
signal (int signal
, __sigfun signal_func
);
916 sys_signal (int signal_num
, __sigfun signal_func
)
918 extern __signal_func_ptr
signal (int signal
, __signal_func_ptr signal_func
);
920 sys_signal (int signal_num
, __signal_func_ptr signal_func
)
921 #else /* not __MRC__ and not __MWERKS__ */
923 #endif /* not __MRC__ and not __MWERKS__ */
925 if (signal_num
!= SIGALRM
)
926 return signal (signal_num
, signal_func
);
930 __sigfun old_signal_func
;
932 __signal_func_ptr old_signal_func
;
936 old_signal_func
= alarm_signal_func
;
937 alarm_signal_func
= signal_func
;
938 return old_signal_func
;
943 /* gettimeofday should return the amount of time (in a timeval
944 structure) since midnight today. The toolbox function Microseconds
945 returns the number of microseconds (in a UnsignedWide value) since
946 the machine was booted. Also making this complicated is WideAdd,
947 WideSubtract, etc. take wide values. */
954 static wide wall_clock_at_epoch
, clicks_at_epoch
;
955 UnsignedWide uw_microseconds
;
957 time_t sys_time (time_t *);
959 /* If this function is called for the first time, record the number
960 of seconds since midnight and the number of microseconds since
961 boot at the time of this first call. */
966 systime
= sys_time (NULL
);
967 /* Store microseconds since midnight in wall_clock_at_epoch. */
968 WideMultiply (systime
, 1000000L, &wall_clock_at_epoch
);
969 Microseconds (&uw_microseconds
);
970 /* Store microseconds since boot in clicks_at_epoch. */
971 clicks_at_epoch
.hi
= uw_microseconds
.hi
;
972 clicks_at_epoch
.lo
= uw_microseconds
.lo
;
975 /* Get time since boot */
976 Microseconds (&uw_microseconds
);
978 /* Convert to time since midnight*/
979 w_microseconds
.hi
= uw_microseconds
.hi
;
980 w_microseconds
.lo
= uw_microseconds
.lo
;
981 WideSubtract (&w_microseconds
, &clicks_at_epoch
);
982 WideAdd (&w_microseconds
, &wall_clock_at_epoch
);
983 tp
->tv_sec
= WideDivide (&w_microseconds
, 1000000L, &tp
->tv_usec
);
991 sleep (unsigned int seconds
)
993 unsigned long time_up
;
996 time_up
= TickCount () + seconds
* 60;
997 while (TickCount () < time_up
)
999 /* Accept no event; just wait. by T.I. */
1000 WaitNextEvent (0, &e
, 30, NULL
);
1005 #endif /* __MRC__ */
1008 /* The time functions adjust time values according to the difference
1009 between the Unix and CW epoches. */
1012 extern struct tm
*gmtime (const time_t *);
1014 sys_gmtime (const time_t *timer
)
1016 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
1018 return gmtime (&unix_time
);
1023 extern struct tm
*localtime (const time_t *);
1025 sys_localtime (const time_t *timer
)
1027 #if __MSL__ >= 0x6000
1028 time_t unix_time
= *timer
;
1030 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
1033 return localtime (&unix_time
);
1038 extern char *ctime (const time_t *);
1040 sys_ctime (const time_t *timer
)
1042 #if __MSL__ >= 0x6000
1043 time_t unix_time
= *timer
;
1045 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
1048 return ctime (&unix_time
);
1053 extern time_t time (time_t *);
1055 sys_time (time_t *timer
)
1057 #if __MSL__ >= 0x6000
1058 time_t mac_time
= time (NULL
);
1060 time_t mac_time
= time (NULL
) - CW_OR_MPW_UNIX_EPOCH_DIFF
;
1070 /* MPW strftime broken for "%p" format */
1075 sys_strftime (char * s
, size_t maxsize
, const char * format
,
1076 const struct tm
* timeptr
)
1078 if (strcmp (format
, "%p") == 0)
1082 if (timeptr
->tm_hour
< 12)
1094 return strftime (s
, maxsize
, format
, timeptr
);
1096 #endif /* __MRC__ */
1099 /* no subprocesses, empty wait */
1109 croak (char *badfunc
)
1111 printf ("%s not yet implemented\r\n", badfunc
);
1117 index (const char * str
, int chr
)
1119 return strchr (str
, chr
);
1124 mktemp (char *template)
1129 len
= strlen (template);
1131 while (k
>= 0 && template[k
] == 'X')
1134 k
++; /* make k index of first 'X' */
1138 /* Zero filled, number of digits equal to the number of X's. */
1139 sprintf (&template[k
], "%0*d", len
-k
, seqnum
++);
1148 /* Emulate getpwuid, getpwnam and others. */
1150 #define PASSWD_FIELD_SIZE 256
1152 static char my_passwd_name
[PASSWD_FIELD_SIZE
];
1153 static char my_passwd_dir
[MAXPATHLEN
+1];
1155 static struct passwd my_passwd
=
1162 /* Initialized by main () in macterm.c to pathname of emacs directory. */
1164 char emacs_passwd_dir
[MAXPATHLEN
+1];
1170 init_emacs_passwd_dir ()
1174 if (getwd (emacs_passwd_dir
) && getwd (my_passwd_dir
))
1176 /* Need pathname of first ancestor that begins with "emacs"
1177 since Mac emacs application is somewhere in the emacs-*
1179 int len
= strlen (emacs_passwd_dir
);
1181 /* j points to the "/" following the directory name being
1184 while (i
>= 0 && !found
)
1186 while (i
>= 0 && emacs_passwd_dir
[i
] != '/')
1188 if (emacs_passwd_dir
[i
] == '/' && i
+5 < len
)
1189 found
= (strncmp (&(emacs_passwd_dir
[i
+1]), "emacs", 5) == 0);
1191 emacs_passwd_dir
[j
+1] = '\0';
1202 /* Setting to "/" probably won't work but set it to something
1204 strcpy (emacs_passwd_dir
, "/");
1205 strcpy (my_passwd_dir
, "/");
1210 static struct passwd emacs_passwd
=
1216 static int my_passwd_inited
= 0;
1224 /* Note: my_passwd_dir initialized in int_emacs_passwd_dir to
1225 directory where Emacs was started. */
1227 owner_name
= (char **) GetResource ('STR ',-16096);
1231 BlockMove ((unsigned char *) *owner_name
,
1232 (unsigned char *) my_passwd_name
,
1234 HUnlock (owner_name
);
1235 p2cstr ((unsigned char *) my_passwd_name
);
1238 my_passwd_name
[0] = 0;
1243 getpwuid (uid_t uid
)
1245 if (!my_passwd_inited
)
1248 my_passwd_inited
= 1;
1256 getpwnam (const char *name
)
1258 if (strcmp (name
, "emacs") == 0)
1259 return &emacs_passwd
;
1261 if (!my_passwd_inited
)
1264 my_passwd_inited
= 1;
1271 /* The functions fork, kill, sigsetmask, sigblock, request_sigio,
1272 setpgrp, setpriority, and unrequest_sigio are defined to be empty
1293 error ("Can't spawn subshell");
1312 request_sigio (void)
1318 unrequest_sigio (void)
1333 pipe (int _fildes
[2])
1340 /* Hard and symbolic links. */
1343 symlink (const char *name1
, const char *name2
)
1351 link (const char *name1
, const char *name2
)
1357 #endif /* ! MAC_OSX */
1359 /* Determine the path name of the file specified by VREFNUM, DIRID,
1360 and NAME and place that in the buffer PATH of length
1363 path_from_vol_dir_name (char *path
, int man_path_len
, short vol_ref_num
,
1364 long dir_id
, ConstStr255Param name
)
1370 if (strlen (name
) > man_path_len
)
1373 memcpy (dir_name
, name
, name
[0]+1);
1374 memcpy (path
, name
, name
[0]+1);
1377 cipb
.dirInfo
.ioDrParID
= dir_id
;
1378 cipb
.dirInfo
.ioNamePtr
= dir_name
;
1382 cipb
.dirInfo
.ioVRefNum
= vol_ref_num
;
1383 cipb
.dirInfo
.ioFDirIndex
= -1;
1384 cipb
.dirInfo
.ioDrDirID
= cipb
.dirInfo
.ioDrParID
;
1385 /* go up to parent each time */
1387 err
= PBGetCatInfo (&cipb
, false);
1392 if (strlen (dir_name
) + strlen (path
) + 1 >= man_path_len
)
1395 strcat (dir_name
, ":");
1396 strcat (dir_name
, path
);
1397 /* attach to front since we're going up directory tree */
1398 strcpy (path
, dir_name
);
1400 while (cipb
.dirInfo
.ioDrDirID
!= fsRtDirID
);
1401 /* stop when we see the volume's root directory */
1403 return 1; /* success */
1409 readlink (const char *path
, char *buf
, int bufsiz
)
1411 char mac_sym_link_name
[MAXPATHLEN
+1];
1414 Boolean target_is_folder
, was_aliased
;
1415 Str255 directory_name
, mac_pathname
;
1418 if (posix_to_mac_pathname (path
, mac_sym_link_name
, MAXPATHLEN
+1) == 0)
1421 c2pstr (mac_sym_link_name
);
1422 err
= FSMakeFSSpec (0, 0, mac_sym_link_name
, &fsspec
);
1429 err
= ResolveAliasFile (&fsspec
, true, &target_is_folder
, &was_aliased
);
1430 if (err
!= noErr
|| !was_aliased
)
1436 if (path_from_vol_dir_name (mac_pathname
, 255, fsspec
.vRefNum
, fsspec
.parID
,
1443 if (mac_to_posix_pathname (mac_pathname
, buf
, bufsiz
) == 0)
1449 return strlen (buf
);
1453 /* Convert a path to one with aliases fully expanded. */
1456 find_true_pathname (const char *path
, char *buf
, int bufsiz
)
1458 char *q
, temp
[MAXPATHLEN
+1];
1462 if (bufsiz
<= 0 || path
== 0 || path
[0] == '\0')
1469 q
= strchr (p
+ 1, '/');
1471 q
= strchr (p
, '/');
1472 len
= 0; /* loop may not be entered, e.g., for "/" */
1477 strncat (temp
, p
, q
- p
);
1478 len
= readlink (temp
, buf
, bufsiz
);
1481 if (strlen (temp
) + 1 > bufsiz
)
1491 if (len
+ strlen (p
) + 1 >= bufsiz
)
1495 return len
+ strlen (p
);
1500 umask (mode_t numask
)
1502 static mode_t mask
= 022;
1503 mode_t oldmask
= mask
;
1510 chmod (const char *path
, mode_t mode
)
1512 /* say it always succeed for now */
1521 return fcntl (oldd
, F_DUPFD
, 0);
1523 /* current implementation of fcntl in fcntl.mac.c simply returns old
1525 return fcntl (oldd
, F_DUPFD
);
1532 /* This is from the original sysdep.c. Emulate BSD dup2. First close
1533 newd if it already exists. Then, attempt to dup oldd. If not
1534 successful, call dup2 recursively until we are, then close the
1535 unsuccessful ones. */
1538 dup2 (int oldd
, int newd
)
1549 ret
= dup2 (oldd
, newd
);
1555 /* let it fail for now */
1572 ioctl (int d
, int request
, void *argp
)
1582 if (fildes
>=0 && fildes
<= 2)
1615 #endif /* __MRC__ */
1619 #if __MSL__ < 0x6000
1627 #endif /* __MWERKS__ */
1629 #endif /* ! MAC_OSX */
1632 /* Return the path to the directory in which Emacs can create
1633 temporary files. The MacOS "temporary items" directory cannot be
1634 used because it removes the file written by a process when it
1635 exits. In that sense it's more like "/dev/null" than "/tmp" (but
1636 again not exactly). And of course Emacs needs to read back the
1637 files written by its subprocesses. So here we write the files to a
1638 directory "Emacs" in the Preferences Folder. This directory is
1639 created if it does not exist. */
1642 get_temp_dir_name ()
1644 static char *temp_dir_name
= NULL
;
1648 Str255 dir_name
, full_path
;
1650 char unix_dir_name
[MAXPATHLEN
+1];
1653 /* Cache directory name with pointer temp_dir_name.
1654 Look for it only the first time. */
1657 err
= FindFolder (kOnSystemDisk
, kPreferencesFolderType
, kCreateFolder
,
1658 &vol_ref_num
, &dir_id
);
1662 if (!path_from_vol_dir_name (full_path
, 255, vol_ref_num
, dir_id
, "\p"))
1665 if (strlen (full_path
) + 6 <= MAXPATHLEN
)
1666 strcat (full_path
, "Emacs:");
1670 if (!mac_to_posix_pathname (full_path
, unix_dir_name
, MAXPATHLEN
+1))
1673 dir
= opendir (unix_dir_name
); /* check whether temp directory exists */
1676 else if (mkdir (unix_dir_name
, 0700) != 0) /* create it if not */
1679 temp_dir_name
= (char *) malloc (strlen (unix_dir_name
) + 1);
1680 strcpy (temp_dir_name
, unix_dir_name
);
1683 return temp_dir_name
;
1688 /* Allocate and construct an array of pointers to strings from a list
1689 of strings stored in a 'STR#' resource. The returned pointer array
1690 is stored in the style of argv and environ: if the 'STR#' resource
1691 contains numString strings, an pointer array with numString+1
1692 elements is returned in which the last entry contains a null
1693 pointer. The pointer to the pointer array is passed by pointer in
1694 parameter t. The resource ID of the 'STR#' resource is passed in
1695 parameter StringListID.
1699 get_string_list (char ***t
, short string_list_id
)
1705 h
= GetResource ('STR#', string_list_id
);
1710 num_strings
= * (short *) p
;
1712 *t
= (char **) malloc (sizeof (char *) * (num_strings
+ 1));
1713 for (i
= 0; i
< num_strings
; i
++)
1715 short length
= *p
++;
1716 (*t
)[i
] = (char *) malloc (length
+ 1);
1717 strncpy ((*t
)[i
], p
, length
);
1718 (*t
)[i
][length
] = '\0';
1721 (*t
)[num_strings
] = 0;
1726 /* Return no string in case GetResource fails. Bug fixed by
1727 Ikegami Tsutomu. Caused MPW build to crash without sym -on
1728 option (no sym -on implies -opt local). */
1729 *t
= (char **) malloc (sizeof (char *));
1736 get_path_to_system_folder ()
1741 Str255 dir_name
, full_path
;
1743 static char system_folder_unix_name
[MAXPATHLEN
+1];
1746 err
= FindFolder (kOnSystemDisk
, kSystemFolderType
, kDontCreateFolder
,
1747 &vol_ref_num
, &dir_id
);
1751 if (!path_from_vol_dir_name (full_path
, 255, vol_ref_num
, dir_id
, "\p"))
1754 if (!mac_to_posix_pathname (full_path
, system_folder_unix_name
,
1758 return system_folder_unix_name
;
1764 #define ENVIRON_STRING_LIST_ID 128
1766 /* Get environment variable definitions from STR# resource. */
1773 get_string_list (&environ
, ENVIRON_STRING_LIST_ID
);
1779 /* Make HOME directory the one Emacs starts up in if not specified
1781 if (getenv ("HOME") == NULL
)
1783 environ
= (char **) realloc (environ
, sizeof (char *) * (i
+ 2));
1786 environ
[i
] = (char *) malloc (strlen (my_passwd_dir
) + 6);
1789 strcpy (environ
[i
], "HOME=");
1790 strcat (environ
[i
], my_passwd_dir
);
1797 /* Make HOME directory the one Emacs starts up in if not specified
1799 if (getenv ("MAIL") == NULL
)
1801 environ
= (char **) realloc (environ
, sizeof (char *) * (i
+ 2));
1804 char * path_to_system_folder
= get_path_to_system_folder ();
1805 environ
[i
] = (char *) malloc (strlen (path_to_system_folder
) + 22);
1808 strcpy (environ
[i
], "MAIL=");
1809 strcat (environ
[i
], path_to_system_folder
);
1810 strcat (environ
[i
], "Eudora Folder/In");
1818 /* Return the value of the environment variable NAME. */
1821 getenv (const char *name
)
1823 int length
= strlen(name
);
1826 for (e
= environ
; *e
!= 0; e
++)
1827 if (strncmp(*e
, name
, length
) == 0 && (*e
)[length
] == '=')
1828 return &(*e
)[length
+ 1];
1830 if (strcmp (name
, "TMPDIR") == 0)
1831 return get_temp_dir_name ();
1838 /* see Interfaces&Libraries:Interfaces:CIncludes:signal.h */
1839 char *sys_siglist
[] =
1841 "Zero is not a signal!!!",
1843 "Interactive user interrupt", /* 2 */ "?",
1844 "Floating point exception", /* 4 */ "?", "?", "?",
1845 "Illegal instruction", /* 8 */ "?", "?", "?", "?", "?", "?", "?",
1846 "Segment violation", /* 16 */ "?", "?", "?", "?", "?", "?", "?",
1847 "?", "?", "?", "?", "?", "?", "?", "?",
1851 char *sys_siglist
[] =
1853 "Zero is not a signal!!!",
1855 "Floating point exception",
1856 "Illegal instruction",
1857 "Interactive user interrupt",
1858 "Segment violation",
1861 #else /* not __MRC__ and not __MWERKS__ */
1863 #endif /* not __MRC__ and not __MWERKS__ */
1866 #include <utsname.h>
1869 uname (struct utsname
*name
)
1872 system_name
= GetString (-16413); /* IM - Resource Manager Reference */
1875 BlockMove (*system_name
, name
->nodename
, (*system_name
)[0]+1);
1876 p2cstr (name
->nodename
);
1884 #include <Processes.h>
1887 /* Event class of HLE sent to subprocess. */
1888 const OSType kEmacsSubprocessSend
= 'ESND';
1890 /* Event class of HLE sent back from subprocess. */
1891 const OSType kEmacsSubprocessReply
= 'ERPY';
1895 mystrchr (char *s
, char c
)
1897 while (*s
&& *s
!= c
)
1925 mystrcpy (char *to
, char *from
)
1937 /* Start a Mac subprocess. Arguments for it is passed in argv (null
1938 terminated). The process should run with the default directory
1939 "workdir", read input from "infn", and write output and error to
1940 "outfn" and "errfn", resp. The Process Manager call
1941 LaunchApplication is used to start the subprocess. We use high
1942 level events as the mechanism to pass arguments to the subprocess
1943 and to make Emacs wait for the subprocess to terminate and pass
1944 back a result code. The bulk of the code here packs the arguments
1945 into one message to be passed together with the high level event.
1946 Emacs also sometimes starts a subprocess using a shell to perform
1947 wildcard filename expansion. Since we don't really have a shell on
1948 the Mac, this case is detected and the starting of the shell is
1949 by-passed. We really need to add code here to do filename
1950 expansion to support such functionality. */
1953 run_mac_command (argv
, workdir
, infn
, outfn
, errfn
)
1954 unsigned char **argv
;
1955 const char *workdir
;
1956 const char *infn
, *outfn
, *errfn
;
1958 #ifdef TARGET_API_MAC_CARBON
1960 #else /* not TARGET_API_MAC_CARBON */
1961 char macappname
[MAXPATHLEN
+1], macworkdir
[MAXPATHLEN
+1];
1962 char macinfn
[MAXPATHLEN
+1], macoutfn
[MAXPATHLEN
+1], macerrfn
[MAXPATHLEN
+1];
1963 int paramlen
, argc
, newargc
, j
, retries
;
1964 char **newargv
, *param
, *p
;
1967 LaunchParamBlockRec lpbr
;
1968 EventRecord send_event
, reply_event
;
1969 RgnHandle cursor_region_handle
;
1971 unsigned long ref_con
, len
;
1973 if (posix_to_mac_pathname (workdir
, macworkdir
, MAXPATHLEN
+1) == 0)
1975 if (posix_to_mac_pathname (infn
, macinfn
, MAXPATHLEN
+1) == 0)
1977 if (posix_to_mac_pathname (outfn
, macoutfn
, MAXPATHLEN
+1) == 0)
1979 if (posix_to_mac_pathname (errfn
, macerrfn
, MAXPATHLEN
+1) == 0)
1982 paramlen
= strlen (macworkdir
) + strlen (macinfn
) + strlen (macoutfn
)
1983 + strlen (macerrfn
) + 4; /* count nulls at end of strings */
1992 /* If a subprocess is invoked with a shell, we receive 3 arguments
1993 of the form: "<path to emacs bins>/sh" "-c" "<path to emacs
1994 bins>/<command> <command args>" */
1995 j
= strlen (argv
[0]);
1996 if (j
>= 3 && strcmp (argv
[0]+j
-3, "/sh") == 0
1997 && argc
== 3 && strcmp (argv
[1], "-c") == 0)
1999 char *command
, *t
, tempmacpathname
[MAXPATHLEN
+1];
2001 /* The arguments for the command in argv[2] are separated by
2002 spaces. Count them and put the count in newargc. */
2003 command
= (char *) alloca (strlen (argv
[2])+2);
2004 strcpy (command
, argv
[2]);
2005 if (command
[strlen (command
) - 1] != ' ')
2006 strcat (command
, " ");
2010 t
= mystrchr (t
, ' ');
2014 t
= mystrchr (t
+1, ' ');
2017 newargv
= (char **) alloca (sizeof (char *) * newargc
);
2020 for (j
= 0; j
< newargc
; j
++)
2022 newargv
[j
] = (char *) alloca (strlen (t
) + 1);
2023 mystrcpy (newargv
[j
], t
);
2026 paramlen
+= strlen (newargv
[j
]) + 1;
2029 if (strncmp (newargv
[0], "~emacs/", 7) == 0)
2031 if (posix_to_mac_pathname (newargv
[0], tempmacpathname
, MAXPATHLEN
+1)
2036 { /* sometimes Emacs call "sh" without a path for the command */
2038 char *t
= (char *) alloca (strlen (newargv
[0]) + 7 + 1);
2039 strcpy (t
, "~emacs/");
2040 strcat (t
, newargv
[0]);
2043 openp (Vexec_path
, build_string (newargv
[0]), EXEC_SUFFIXES
, &path
,
2048 if (posix_to_mac_pathname (XSTRING (path
)->data
, tempmacpathname
,
2052 strcpy (macappname
, tempmacpathname
);
2056 if (posix_to_mac_pathname (argv
[0], macappname
, MAXPATHLEN
+1) == 0)
2059 newargv
= (char **) alloca (sizeof (char *) * argc
);
2061 for (j
= 1; j
< argc
; j
++)
2063 if (strncmp (argv
[j
], "~emacs/", 7) == 0)
2065 char *t
= strchr (argv
[j
], ' ');
2068 char tempcmdname
[MAXPATHLEN
+1], tempmaccmdname
[MAXPATHLEN
+1];
2069 strncpy (tempcmdname
, argv
[j
], t
-argv
[j
]);
2070 tempcmdname
[t
-argv
[j
]] = '\0';
2071 if (posix_to_mac_pathname (tempcmdname
, tempmaccmdname
,
2074 newargv
[j
] = (char *) alloca (strlen (tempmaccmdname
)
2076 strcpy (newargv
[j
], tempmaccmdname
);
2077 strcat (newargv
[j
], t
);
2081 char tempmaccmdname
[MAXPATHLEN
+1];
2082 if (posix_to_mac_pathname (argv
[j
], tempmaccmdname
,
2085 newargv
[j
] = (char *) alloca (strlen (tempmaccmdname
)+1);
2086 strcpy (newargv
[j
], tempmaccmdname
);
2090 newargv
[j
] = argv
[j
];
2091 paramlen
+= strlen (newargv
[j
]) + 1;
2095 /* After expanding all the arguments, we now know the length of the
2096 parameter block to be sent to the subprocess as a message
2097 attached to the HLE. */
2098 param
= (char *) malloc (paramlen
+ 1);
2104 /* first byte of message contains number of arguments for command */
2105 strcpy (p
, macworkdir
);
2106 p
+= strlen (macworkdir
);
2108 /* null terminate strings sent so it's possible to use strcpy over there */
2109 strcpy (p
, macinfn
);
2110 p
+= strlen (macinfn
);
2112 strcpy (p
, macoutfn
);
2113 p
+= strlen (macoutfn
);
2115 strcpy (p
, macerrfn
);
2116 p
+= strlen (macerrfn
);
2118 for (j
= 1; j
< newargc
; j
++)
2120 strcpy (p
, newargv
[j
]);
2121 p
+= strlen (newargv
[j
]);
2125 c2pstr (macappname
);
2127 iErr
= FSMakeFSSpec (0, 0, macappname
, &spec
);
2135 lpbr
.launchBlockID
= extendedBlock
;
2136 lpbr
.launchEPBLength
= extendedBlockLen
;
2137 lpbr
.launchControlFlags
= launchContinue
+ launchNoFileFlags
;
2138 lpbr
.launchAppSpec
= &spec
;
2139 lpbr
.launchAppParameters
= NULL
;
2141 iErr
= LaunchApplication (&lpbr
); /* call the subprocess */
2148 send_event
.what
= kHighLevelEvent
;
2149 send_event
.message
= kEmacsSubprocessSend
;
2150 /* Event ID stored in "where" unused */
2153 /* OS may think current subprocess has terminated if previous one
2154 terminated recently. */
2157 iErr
= PostHighLevelEvent (&send_event
, &lpbr
.launchProcessSN
, 0, param
,
2158 paramlen
+ 1, receiverIDisPSN
);
2160 while (iErr
== sessClosedErr
&& retries
-- > 0);
2168 cursor_region_handle
= NewRgn ();
2170 /* Wait for the subprocess to finish, when it will send us a ERPY
2171 high level event. */
2173 if (WaitNextEvent (highLevelEventMask
, &reply_event
, 180,
2174 cursor_region_handle
)
2175 && reply_event
.message
== kEmacsSubprocessReply
)
2178 /* The return code is sent through the refCon */
2179 iErr
= AcceptHighLevelEvent (&targ
, &ref_con
, NULL
, &len
);
2182 DisposeHandle ((Handle
) cursor_region_handle
);
2187 DisposeHandle ((Handle
) cursor_region_handle
);
2191 #endif /* not TARGET_API_MAC_CARBON */
2196 opendir (const char *dirname
)
2198 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
2199 char mac_pathname
[MAXPATHLEN
+1], vol_name
[MAXPATHLEN
+1];
2203 int len
, vol_name_len
;
2205 if (find_true_pathname (dirname
, true_pathname
, MAXPATHLEN
+1) == -1)
2208 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
2210 fully_resolved_name
[len
] = '\0';
2212 strcpy (fully_resolved_name
, true_pathname
);
2214 dirp
= (DIR *) malloc (sizeof(DIR));
2218 /* Handle special case when dirname is "/": sets up for readir to
2219 get all mount volumes. */
2220 if (strcmp (fully_resolved_name
, "/") == 0)
2222 dirp
->getting_volumes
= 1; /* special all mounted volumes DIR struct */
2223 dirp
->current_index
= 1; /* index for first volume */
2227 /* Handle typical cases: not accessing all mounted volumes. */
2228 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
2231 /* Emacs calls opendir without the trailing '/', Mac needs trailing ':' */
2232 len
= strlen (mac_pathname
);
2233 if (mac_pathname
[len
- 1] != ':' && len
< MAXPATHLEN
)
2234 strcat (mac_pathname
, ":");
2236 /* Extract volume name */
2237 vol_name_len
= strchr (mac_pathname
, ':') - mac_pathname
;
2238 strncpy (vol_name
, mac_pathname
, vol_name_len
);
2239 vol_name
[vol_name_len
] = '\0';
2240 strcat (vol_name
, ":");
2242 c2pstr (mac_pathname
);
2243 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
2244 /* using full pathname so vRefNum and DirID ignored */
2245 cipb
.hFileInfo
.ioVRefNum
= 0;
2246 cipb
.hFileInfo
.ioDirID
= 0;
2247 cipb
.hFileInfo
.ioFDirIndex
= 0;
2248 /* set to 0 to get information about specific dir or file */
2250 errno
= PBGetCatInfo (&cipb
, false);
2257 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x10)) /* bit 4 = 1 for directories */
2258 return 0; /* not a directory */
2260 dirp
->dir_id
= cipb
.dirInfo
.ioDrDirID
; /* used later in readdir */
2261 dirp
->getting_volumes
= 0;
2262 dirp
->current_index
= 1; /* index for first file/directory */
2265 vpb
.ioNamePtr
= vol_name
;
2266 /* using full pathname so vRefNum and DirID ignored */
2268 vpb
.ioVolIndex
= -1;
2269 errno
= PBHGetVInfo ((union HParamBlockRec
*) &vpb
, false);
2276 dirp
->vol_ref_num
= vpb
.ioVRefNum
;
2293 HParamBlockRec hpblock
;
2295 static struct dirent s_dirent
;
2296 static Str255 s_name
;
2300 /* Handle the root directory containing the mounted volumes. Call
2301 PBHGetVInfo specifying an index to obtain the info for a volume.
2302 PBHGetVInfo returns an error when it receives an index beyond the
2303 last volume, at which time we should return a nil dirent struct
2305 if (dp
->getting_volumes
)
2307 hpblock
.volumeParam
.ioNamePtr
= s_name
;
2308 hpblock
.volumeParam
.ioVRefNum
= 0;
2309 hpblock
.volumeParam
.ioVolIndex
= dp
->current_index
;
2311 errno
= PBHGetVInfo (&hpblock
, false);
2319 strcat (s_name
, "/"); /* need "/" for stat to work correctly */
2321 dp
->current_index
++;
2323 s_dirent
.d_ino
= hpblock
.volumeParam
.ioVRefNum
;
2324 s_dirent
.d_name
= s_name
;
2330 cipb
.hFileInfo
.ioVRefNum
= dp
->vol_ref_num
;
2331 cipb
.hFileInfo
.ioNamePtr
= s_name
;
2332 /* location to receive filename returned */
2334 /* return only visible files */
2338 cipb
.hFileInfo
.ioDirID
= dp
->dir_id
;
2339 /* directory ID found by opendir */
2340 cipb
.hFileInfo
.ioFDirIndex
= dp
->current_index
;
2342 errno
= PBGetCatInfo (&cipb
, false);
2349 /* insist on an visibile entry */
2350 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* directory? */
2351 done
= !(cipb
.dirInfo
.ioDrUsrWds
.frFlags
& fInvisible
);
2353 done
= !(cipb
.hFileInfo
.ioFlFndrInfo
.fdFlags
& fInvisible
);
2355 dp
->current_index
++;
2368 s_dirent
.d_ino
= cipb
.dirInfo
.ioDrDirID
;
2369 /* value unimportant: non-zero for valid file */
2370 s_dirent
.d_name
= s_name
;
2380 char mac_pathname
[MAXPATHLEN
+1];
2381 Str255 directory_name
;
2385 if (path_from_vol_dir_name (mac_pathname
, 255, 0, 0, "\p") == 0)
2388 if (mac_to_posix_pathname (mac_pathname
, path
, MAXPATHLEN
+1) == 0)
2394 #endif /* ! MAC_OSX */
2398 initialize_applescript ()
2403 /* if open fails, as_scripting_component is set to NULL. Its
2404 subsequent use in OSA calls will fail with badComponentInstance
2406 as_scripting_component
= OpenDefaultComponent (kOSAComponentType
,
2407 kAppleScriptSubtype
);
2409 null_desc
.descriptorType
= typeNull
;
2410 null_desc
.dataHandle
= 0;
2411 osaerror
= OSAMakeContext (as_scripting_component
, &null_desc
,
2412 kOSANullScript
, &as_script_context
);
2414 as_script_context
= kOSANullScript
;
2415 /* use default context if create fails */
2419 void terminate_applescript()
2421 OSADispose (as_scripting_component
, as_script_context
);
2422 CloseComponent (as_scripting_component
);
2426 /* Compile and execute the AppleScript SCRIPT and return the error
2427 status as function value. A zero is returned if compilation and
2428 execution is successful, in which case RESULT returns a pointer to
2429 a string containing the resulting script value. Otherwise, the Mac
2430 error code is returned and RESULT returns a pointer to an error
2431 string. In both cases the caller should deallocate the storage
2432 used by the string pointed to by RESULT if it is non-NULL. For
2433 documentation on the MacOS scripting architecture, see Inside
2434 Macintosh - Interapplication Communications: Scripting Components. */
2437 do_applescript (char *script
, char **result
)
2439 AEDesc script_desc
, result_desc
, error_desc
;
2446 error
= AECreateDesc (typeChar
, script
, strlen(script
), &script_desc
);
2450 osaerror
= OSADoScript (as_scripting_component
, &script_desc
, kOSANullScript
,
2451 typeChar
, kOSAModeNull
, &result_desc
);
2453 if (osaerror
== errOSAScriptError
)
2455 /* error executing AppleScript: retrieve error message */
2456 if (!OSAScriptError (as_scripting_component
, kOSAErrorMessage
, typeChar
,
2459 #if TARGET_API_MAC_CARBON
2460 length
= AEGetDescDataSize (&error_desc
);
2461 *result
= (char *) xmalloc (length
+ 1);
2464 AEGetDescData (&error_desc
, *result
, length
);
2465 *(*result
+ length
) = '\0';
2467 #else /* not TARGET_API_MAC_CARBON */
2468 HLock (error_desc
.dataHandle
);
2469 length
= GetHandleSize(error_desc
.dataHandle
);
2470 *result
= (char *) xmalloc (length
+ 1);
2473 memcpy (*result
, *(error_desc
.dataHandle
), length
);
2474 *(*result
+ length
) = '\0';
2476 HUnlock (error_desc
.dataHandle
);
2477 #endif /* not TARGET_API_MAC_CARBON */
2478 AEDisposeDesc (&error_desc
);
2481 else if (osaerror
== noErr
) /* success: retrieve resulting script value */
2483 #if TARGET_API_MAC_CARBON
2484 length
= AEGetDescDataSize (&result_desc
);
2485 *result
= (char *) xmalloc (length
+ 1);
2488 AEGetDescData (&result_desc
, *result
, length
);
2489 *(*result
+ length
) = '\0';
2491 #else /* not TARGET_API_MAC_CARBON */
2492 HLock (result_desc
.dataHandle
);
2493 length
= GetHandleSize(result_desc
.dataHandle
);
2494 *result
= (char *) xmalloc (length
+ 1);
2497 memcpy (*result
, *(result_desc
.dataHandle
), length
);
2498 *(*result
+ length
) = '\0';
2500 HUnlock (result_desc
.dataHandle
);
2501 #endif /* not TARGET_API_MAC_CARBON */
2504 AEDisposeDesc (&script_desc
);
2505 AEDisposeDesc (&result_desc
);
2511 DEFUN ("do-applescript", Fdo_applescript
, Sdo_applescript
, 1, 1, 0,
2512 doc
: /* Compile and execute AppleScript SCRIPT and retrieve and return the result.
2513 If compilation and execution are successful, the resulting script
2514 value is returned as a string. Otherwise the function aborts and
2515 displays the error message returned by the AppleScript scripting
2520 char *result
, *temp
;
2521 Lisp_Object lisp_result
;
2524 CHECK_STRING (script
);
2526 status
= do_applescript (XSTRING (script
)->data
, &result
);
2530 error ("AppleScript error %ld", status
);
2533 /* Unfortunately only OSADoScript in do_applescript knows how
2534 how large the resulting script value or error message is
2535 going to be and therefore as caller memory must be
2536 deallocated here. It is necessary to free the error
2537 message before calling error to avoid a memory leak. */
2538 temp
= (char *) alloca (strlen (result
) + 1);
2539 strcpy (temp
, result
);
2546 lisp_result
= build_string (result
);
2553 DEFUN ("mac-file-name-to-posix", Fmac_file_name_to_posix
,
2554 Smac_file_name_to_posix
, 1, 1, 0,
2555 doc
: /* Convert Macintosh filename to Posix form. */)
2557 Lisp_Object mac_filename
;
2559 char posix_filename
[MAXPATHLEN
+1];
2561 CHECK_STRING (mac_filename
);
2563 if (mac_to_posix_pathname (XSTRING (mac_filename
)->data
, posix_filename
,
2565 return build_string (posix_filename
);
2571 DEFUN ("posix-file-name-to-mac", Fposix_file_name_to_mac
,
2572 Sposix_file_name_to_mac
, 1, 1, 0,
2573 doc
: /* Convert Posix filename to Mac form. */)
2575 Lisp_Object posix_filename
;
2577 char mac_filename
[MAXPATHLEN
+1];
2579 CHECK_STRING (posix_filename
);
2581 if (posix_to_mac_pathname (XSTRING (posix_filename
)->data
, mac_filename
,
2583 return build_string (mac_filename
);
2589 /* set interprogram-paste-function to mac-paste-function in mac-win.el
2590 to enable Emacs to obtain the contents of the Mac clipboard. */
2591 DEFUN ("mac-paste-function", Fmac_paste_function
, Smac_paste_function
, 0, 0, 0,
2592 doc
: /* Return the contents of the Mac clipboard as a string. */)
2595 #if TARGET_API_MAC_CARBON
2597 ScrapFlavorFlags sff
;
2602 if (GetCurrentScrap (&scrap
) != noErr
)
2605 if (GetScrapFlavorFlags (scrap
, kScrapFlavorTypeText
, &sff
) != noErr
)
2608 if (GetScrapFlavorSize (scrap
, kScrapFlavorTypeText
, &s
) != noErr
)
2611 if ((data
= (char*) alloca (s
)) == NULL
)
2614 if (GetScrapFlavorData (scrap
, kScrapFlavorTypeText
, &s
, data
) != noErr
2618 /* Emacs expects clipboard contents have Unix-style eol's */
2619 for (i
= 0; i
< s
; i
++)
2620 if (data
[i
] == '\r')
2623 return make_string (data
, s
);
2624 #else /* not TARGET_API_MAC_CARBON */
2627 long scrap_offset
, rc
, i
;
2629 my_handle
= NewHandle (0); /* allocate 0-length data area */
2631 rc
= GetScrap (my_handle
, 'TEXT', &scrap_offset
);
2637 /* Emacs expects clipboard contents have Unix-style eol's */
2638 for (i
= 0; i
< rc
; i
++)
2639 if ((*my_handle
)[i
] == '\r')
2640 (*my_handle
)[i
] = '\n';
2642 value
= make_string (*my_handle
, rc
);
2644 HUnlock (my_handle
);
2646 DisposeHandle (my_handle
);
2649 #endif /* not TARGET_API_MAC_CARBON */
2653 /* set interprogram-cut-function to mac-cut-function in mac-win.el
2654 to enable Emacs to write the top of the kill-ring to the Mac clipboard. */
2655 DEFUN ("mac-cut-function", Fmac_cut_function
, Smac_cut_function
, 1, 2, 0,
2656 doc
: /* Put the value of the string parameter to the Mac clipboard. */)
2658 Lisp_Object value
, push
;
2663 /* fixme: ignore the push flag for now */
2665 CHECK_STRING (value
);
2667 len
= XSTRING (value
)->size
;
2668 buf
= (char *) alloca (len
+1);
2669 bcopy (XSTRING (value
)->data
, buf
, len
);
2672 /* convert to Mac-style eol's before sending to clipboard */
2673 for (i
= 0; i
< len
; i
++)
2677 #if TARGET_API_MAC_CARBON
2680 ClearCurrentScrap ();
2681 if (GetCurrentScrap (&scrap
) != noErr
)
2682 error ("cannot get current scrap");
2684 if (PutScrapFlavor (scrap
, kScrapFlavorTypeText
, kScrapFlavorMaskNone
, len
,
2686 error ("cannot put to scrap");
2688 #else /* not TARGET_API_MAC_CARBON */
2690 PutScrap (len
, 'TEXT', buf
);
2691 #endif /* not TARGET_API_MAC_CARBON */
2697 DEFUN ("x-selection-exists-p", Fx_selection_exists_p
, Sx_selection_exists_p
,
2699 doc
: /* Whether there is an owner for the given X Selection.
2700 The arg should be the name of the selection in question, typically one of
2701 the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.
2702 (Those are literal upper-case symbol names, since that's what X expects.)
2703 For convenience, the symbol nil is the same as `PRIMARY',
2704 and t is the same as `SECONDARY'. */)
2706 Lisp_Object selection
;
2708 CHECK_SYMBOL (selection
);
2710 /* Return nil for PRIMARY and SECONDARY selections; for CLIPBOARD, check
2711 if the clipboard currently has valid text format contents. */
2713 if (EQ (selection
, QCLIPBOARD
))
2715 Lisp_Object val
= Qnil
;
2717 #if TARGET_API_MAC_CARBON
2719 ScrapFlavorFlags sff
;
2721 if (GetCurrentScrap (&scrap
) == noErr
)
2722 if (GetScrapFlavorFlags (scrap
, kScrapFlavorTypeText
, &sff
) == noErr
)
2724 #else /* not TARGET_API_MAC_CARBON */
2726 long rc
, scrap_offset
;
2728 my_handle
= NewHandle (0);
2730 rc
= GetScrap (my_handle
, 'TEXT', &scrap_offset
);
2734 DisposeHandle (my_handle
);
2735 #endif /* not TARGET_API_MAC_CARBON */
2746 QCLIPBOARD
= intern ("CLIPBOARD");
2747 staticpro (&QCLIPBOARD
);
2749 defsubr (&Smac_paste_function
);
2750 defsubr (&Smac_cut_function
);
2752 defsubr (&Sx_selection_exists_p
);
2755 defsubr (&Sdo_applescript
);
2756 defsubr (&Smac_file_name_to_posix
);
2757 defsubr (&Sposix_file_name_to_mac
);