1 /* Unix emulation routines for GNU Emacs on the Mac OS.
2 Copyright (C) 2000 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@users.sourceforge.net). */
32 #include <sys/param.h>
39 #include <TextUtils.h>
41 #include <Resources.h>
46 #include <AppleScript.h>
50 #include "sysselect.h"
53 Lisp_Object QCLIPBOARD
;
55 /* An instance of the AppleScript component. */
56 static ComponentInstance as_scripting_component
;
57 /* The single script context used for all script executions. */
58 static OSAID as_script_context
;
61 /* When converting from Mac to Unix pathnames, /'s in folder names are
62 converted to :'s. This function, used in copying folder names,
63 performs a strncat and converts all character a to b in the copy of
64 the string s2 appended to the end of s1. */
67 string_cat_and_replace (char *s1
, const char *s2
, int n
, char a
, char b
)
75 for (i
= 0; i
< l2
; i
++)
84 /* Convert a Mac pathname to Unix form. A Mac full pathname is one
85 that does not begin with a ':' and contains at least one ':'. A Mac
86 full pathname causes an '/' to be prepended to the Unix pathname.
87 The algorithm for the rest of the pathname is as follows:
88 For each segment between two ':',
89 if it is non-null, copy as is and then add a '/' at the end,
90 otherwise, insert a "../" into the Unix pathname.
91 Returns 1 if successful; 0 if fails. */
94 mac_to_posix_pathname (const char *mfn
, char *ufn
, int ufnbuflen
)
96 const char *p
, *q
, *pe
;
103 p
= strchr (mfn
, ':');
104 if (p
!= 0 && p
!= mfn
) /* full pathname */
111 pe
= mfn
+ strlen (mfn
);
118 { /* two consecutive ':' */
119 if (strlen (ufn
) + 3 >= ufnbuflen
)
125 if (strlen (ufn
) + (q
- p
) + 1 >= ufnbuflen
)
127 string_cat_and_replace (ufn
, p
, q
- p
, '/', ':');
134 if (strlen (ufn
) + (pe
- p
) >= ufnbuflen
)
136 string_cat_and_replace (ufn
, p
, pe
- p
, '/', ':');
137 /* no separator for last one */
146 extern char *get_temp_dir_name ();
149 /* Convert a Unix pathname to Mac form. Approximately reverse of the
150 above in algorithm. */
153 posix_to_mac_pathname (const char *ufn
, char *mfn
, int mfnbuflen
)
155 const char *p
, *q
, *pe
;
156 char expanded_pathname
[MAXPATHLEN
+1];
165 /* Check for and handle volume names. Last comparison: strangely
166 somewhere "/.emacs" is passed. A temporary fix for now. */
167 if (*p
== '/' && strchr (p
+1, '/') == NULL
&& strcmp (p
, "/.emacs") != 0)
169 if (strlen (p
) + 1 > mfnbuflen
)
176 /* expand to emacs dir found by init_emacs_passwd_dir */
177 if (strncmp (p
, "~emacs/", 7) == 0)
179 struct passwd
*pw
= getpwnam ("emacs");
181 if (strlen (pw
->pw_dir
) + strlen (p
) > MAXPATHLEN
)
183 strcpy (expanded_pathname
, pw
->pw_dir
);
184 strcat (expanded_pathname
, p
);
185 p
= expanded_pathname
;
186 /* now p points to the pathname with emacs dir prefix */
188 else if (strncmp (p
, "/tmp/", 5) == 0)
190 char *t
= get_temp_dir_name ();
192 if (strlen (t
) + strlen (p
) > MAXPATHLEN
)
194 strcpy (expanded_pathname
, t
);
195 strcat (expanded_pathname
, p
);
196 p
= expanded_pathname
;
197 /* now p points to the pathname with emacs dir prefix */
199 else if (*p
!= '/') /* relative pathname */
211 if (q
- p
== 2 && *p
== '.' && *(p
+1) == '.')
213 if (strlen (mfn
) + 1 >= mfnbuflen
)
219 if (strlen (mfn
) + (q
- p
) + 1 >= mfnbuflen
)
221 string_cat_and_replace (mfn
, p
, q
- p
, ':', '/');
228 if (strlen (mfn
) + (pe
- p
) >= mfnbuflen
)
230 string_cat_and_replace (mfn
, p
, pe
- p
, ':', '/');
239 /* The following functions with "sys_" prefix are stubs to Unix
240 functions that have already been implemented by CW or MPW. The
241 calls to them in Emacs source course are #define'd to call the sys_
242 versions by the header files s-mac.h. In these stubs pathnames are
243 converted between their Unix and Mac forms. */
246 /* Unix epoch is Jan 1, 1970 while Mac epoch is Jan 1, 1904: 66 years
247 + 17 leap days. These are for adjusting time values returned by
248 MacOS Toolbox functions. */
250 #define MAC_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
253 #ifndef CODEWARRIOR_VERSION_6
254 /* CW Pro 5 epoch is Jan 1, 1900 (aaarghhhhh!); remember, 1900 is not
255 a leap year! This is for adjusting time_t values returned by MSL
257 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 70 + 17) * 24 * 60 * 60)
259 /* CW changes Pro 6 to following Unix! */
260 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
263 /* MPW library functions follow Unix (confused?). */
264 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
270 /* Define our own stat function for both MrC and CW. The reason for
271 doing this: "stat" is both the name of a struct and function name:
272 can't use the same trick like that for sys_open, sys_close, etc. to
273 redirect Emacs's calls to our own version that converts Unix style
274 filenames to Mac style filename because all sorts of compilation
275 errors will be generated if stat is #define'd to be sys_stat. */
278 stat_noalias (const char *path
, struct stat
*buf
)
280 char mac_pathname
[MAXPATHLEN
+1];
283 if (posix_to_mac_pathname (path
, mac_pathname
, MAXPATHLEN
+1) == 0)
286 c2pstr (mac_pathname
);
287 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
288 cipb
.hFileInfo
.ioVRefNum
= 0;
289 cipb
.hFileInfo
.ioDirID
= 0;
290 cipb
.hFileInfo
.ioFDirIndex
= 0;
291 /* set to 0 to get information about specific dir or file */
293 errno
= PBGetCatInfo (&cipb
, false);
294 if (errno
== -43) /* -43: fnfErr defined in Errors.h */
299 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* bit 4 = 1 for directories */
301 buf
->st_mode
= S_IFDIR
| S_IREAD
| S_IEXEC
;
303 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x1))
304 buf
->st_mode
|= S_IWRITE
; /* bit 1 = 1 for locked files/directories */
305 buf
->st_ino
= cipb
.dirInfo
.ioDrDirID
;
306 buf
->st_dev
= cipb
.dirInfo
.ioVRefNum
;
307 buf
->st_size
= cipb
.dirInfo
.ioDrNmFls
;
308 /* size of dir = number of files and dirs */
311 = cipb
.dirInfo
.ioDrMdDat
- MAC_UNIX_EPOCH_DIFF
;
312 buf
->st_ctime
= cipb
.dirInfo
.ioDrCrDat
- MAC_UNIX_EPOCH_DIFF
;
316 buf
->st_mode
= S_IFREG
| S_IREAD
;
317 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x1))
318 buf
->st_mode
|= S_IWRITE
; /* bit 1 = 1 for locked files/directories */
319 if (cipb
.hFileInfo
.ioFlFndrInfo
.fdType
== 'APPL')
320 buf
->st_mode
|= S_IEXEC
;
321 buf
->st_ino
= cipb
.hFileInfo
.ioDirID
;
322 buf
->st_dev
= cipb
.hFileInfo
.ioVRefNum
;
323 buf
->st_size
= cipb
.hFileInfo
.ioFlLgLen
;
326 = cipb
.hFileInfo
.ioFlMdDat
- MAC_UNIX_EPOCH_DIFF
;
327 buf
->st_ctime
= cipb
.hFileInfo
.ioFlCrDat
- MAC_UNIX_EPOCH_DIFF
;
330 if (cipb
.hFileInfo
.ioFlFndrInfo
.fdFlags
& 0x8000)
332 /* identify alias files as symlinks */
333 buf
->st_mode
&= ~S_IFREG
;
334 buf
->st_mode
|= S_IFLNK
;
338 buf
->st_uid
= getuid ();
339 buf
->st_gid
= getgid ();
347 lstat (const char *path
, struct stat
*buf
)
350 char true_pathname
[MAXPATHLEN
+1];
352 /* Try looking for the file without resolving aliases first. */
353 if ((result
= stat_noalias (path
, buf
)) >= 0)
356 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
359 return stat_noalias (true_pathname
, buf
);
364 stat (const char *path
, struct stat
*sb
)
367 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
370 if ((result
= stat_noalias (path
, sb
)) >= 0 &&
371 ! (sb
->st_mode
& S_IFLNK
))
374 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
377 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
380 fully_resolved_name
[len
] = '\0';
381 /* in fact our readlink terminates strings */
382 return lstat (fully_resolved_name
, sb
);
385 return lstat (true_pathname
, sb
);
390 /* CW defines fstat in stat.mac.c while MPW does not provide this
391 function. Without the information of how to get from a file
392 descriptor in MPW StdCLib to a Mac OS file spec, it should be hard
393 to implement this function. Fortunately, there is only one place
394 where this function is called in our configuration: in fileio.c,
395 where only the st_dev and st_ino fields are used to determine
396 whether two fildes point to different i-nodes to prevent copying
397 a file onto itself equal. What we have here probably needs
401 fstat (int fildes
, struct stat
*buf
)
404 buf
->st_ino
= fildes
;
405 buf
->st_mode
= S_IFREG
; /* added by T.I. for the copy-file */
406 return 0; /* success */
411 /* Adapted from Think Reference code example. */
414 mkdir (const char *dirname
, int mode
)
419 char true_pathname
[MAXPATHLEN
+1], mac_pathname
[MAXPATHLEN
+1];
421 if (find_true_pathname (dirname
, true_pathname
, MAXPATHLEN
+1) == -1)
424 if (posix_to_mac_pathname (true_pathname
, mac_pathname
, MAXPATHLEN
+1) == 0)
427 c2pstr (mac_pathname
);
428 hfpb
.ioNamePtr
= mac_pathname
;
429 hfpb
.ioVRefNum
= 0; /* ignored unless name is invalid */
430 hfpb
.ioDirID
= 0; /* parent is the root */
432 errno
= PBDirCreate ((HParmBlkPtr
) &hfpb
, false);
433 /* just return the Mac OSErr code for now */
434 return errno
== noErr
? 0 : -1;
439 sys_rmdir (const char *dirname
)
442 char mac_pathname
[MAXPATHLEN
+1];
444 if (posix_to_mac_pathname (dirname
, mac_pathname
, MAXPATHLEN
+1) == 0)
447 c2pstr (mac_pathname
);
448 hfpb
.ioNamePtr
= mac_pathname
;
449 hfpb
.ioVRefNum
= 0; /* ignored unless name is invalid */
450 hfpb
.ioDirID
= 0; /* parent is the root */
452 errno
= PBHDelete ((HParmBlkPtr
) &hfpb
, false);
453 return errno
== noErr
? 0 : -1;
458 /* No implementation yet. */
460 execvp (const char *path
, ...)
468 utime (const char *path
, const struct utimbuf
*times
)
470 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
472 char mac_pathname
[MAXPATHLEN
+1];
475 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
478 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
480 fully_resolved_name
[len
] = '\0';
482 strcpy (fully_resolved_name
, true_pathname
);
484 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
487 c2pstr (mac_pathname
);
488 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
489 cipb
.hFileInfo
.ioVRefNum
= 0;
490 cipb
.hFileInfo
.ioDirID
= 0;
491 cipb
.hFileInfo
.ioFDirIndex
= 0;
492 /* set to 0 to get information about specific dir or file */
494 errno
= PBGetCatInfo (&cipb
, false);
498 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* bit 4 = 1 for directories */
501 cipb
.dirInfo
.ioDrMdDat
= times
->modtime
+ MAC_UNIX_EPOCH_DIFF
;
503 GetDateTime (&cipb
.dirInfo
.ioDrMdDat
);
508 cipb
.hFileInfo
.ioFlMdDat
= times
->modtime
+ MAC_UNIX_EPOCH_DIFF
;
510 GetDateTime (&cipb
.hFileInfo
.ioFlMdDat
);
513 errno
= PBSetCatInfo (&cipb
, false);
514 return errno
== noErr
? 0 : -1;
528 /* Like stat, but test for access mode in hfpb.ioFlAttrib */
530 access (const char *path
, int mode
)
532 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
534 char mac_pathname
[MAXPATHLEN
+1];
537 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
540 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
542 fully_resolved_name
[len
] = '\0';
544 strcpy (fully_resolved_name
, true_pathname
);
546 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
549 c2pstr (mac_pathname
);
550 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
551 cipb
.hFileInfo
.ioVRefNum
= 0;
552 cipb
.hFileInfo
.ioDirID
= 0;
553 cipb
.hFileInfo
.ioFDirIndex
= 0;
554 /* set to 0 to get information about specific dir or file */
556 errno
= PBGetCatInfo (&cipb
, false);
560 if (mode
== F_OK
) /* got this far, file exists */
564 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* path refers to a directory */
568 if (cipb
.hFileInfo
.ioFlFndrInfo
.fdType
== 'APPL')
575 return (cipb
.hFileInfo
.ioFlAttrib
& 0x1) ? -1 : 0;
576 /* don't allow if lock bit is on */
582 #define DEV_NULL_FD 0x10000
586 sys_open (const char *path
, int oflag
)
588 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
590 char mac_pathname
[MAXPATHLEN
+1];
592 if (strcmp (path
, "/dev/null") == 0)
593 return DEV_NULL_FD
; /* some bogus fd to be ignored in write */
595 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
598 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
600 fully_resolved_name
[len
] = '\0';
602 strcpy (fully_resolved_name
, true_pathname
);
604 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
609 int res
= open (mac_pathname
, oflag
);
610 /* if (oflag == O_WRONLY || oflag == O_RDWR) */
612 fsetfileinfo (mac_pathname
, 'EMAx', 'TEXT');
615 return open (mac_pathname
, oflag
);
623 sys_creat (const char *path
, mode_t mode
)
625 char true_pathname
[MAXPATHLEN
+1];
627 char mac_pathname
[MAXPATHLEN
+1];
629 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
632 if (!posix_to_mac_pathname (true_pathname
, mac_pathname
, MAXPATHLEN
+1))
637 int result
= creat (mac_pathname
);
638 fsetfileinfo (mac_pathname
, 'EMAx', 'TEXT');
641 return creat (mac_pathname
, mode
);
649 sys_unlink (const char *path
)
651 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
653 char mac_pathname
[MAXPATHLEN
+1];
655 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
658 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
660 fully_resolved_name
[len
] = '\0';
662 strcpy (fully_resolved_name
, true_pathname
);
664 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
667 return unlink (mac_pathname
);
673 sys_read (int fildes
, char *buf
, int count
)
675 if (fildes
== 0) /* this should not be used for console input */
678 #ifdef CODEWARRIOR_VERSION_6
679 return _read (fildes
, buf
, count
);
681 return read (fildes
, buf
, count
);
688 sys_write (int fildes
, const char *buf
, int count
)
690 if (fildes
== DEV_NULL_FD
)
693 #ifdef CODEWARRIOR_VERSION_6
694 return _write (fildes
, buf
, count
);
696 return write (fildes
, buf
, count
);
703 sys_rename (const char * old_name
, const char * new_name
)
705 char true_old_pathname
[MAXPATHLEN
+1], true_new_pathname
[MAXPATHLEN
+1];
706 char fully_resolved_old_name
[MAXPATHLEN
+1];
708 char mac_old_name
[MAXPATHLEN
+1], mac_new_name
[MAXPATHLEN
+1];
710 if (find_true_pathname (old_name
, true_old_pathname
, MAXPATHLEN
+1) == -1)
713 len
= readlink (true_old_pathname
, fully_resolved_old_name
, MAXPATHLEN
);
715 fully_resolved_old_name
[len
] = '\0';
717 strcpy (fully_resolved_old_name
, true_old_pathname
);
719 if (find_true_pathname (new_name
, true_new_pathname
, MAXPATHLEN
+1) == -1)
722 if (strcmp (fully_resolved_old_name
, true_new_pathname
) == 0)
725 if (!posix_to_mac_pathname (fully_resolved_old_name
,
730 if (!posix_to_mac_pathname(true_new_pathname
, mac_new_name
, MAXPATHLEN
+1))
733 /* If a file with new_name already exists, rename deletes the old
734 file in Unix. CW version fails in these situation. So we add a
735 call to unlink here. */
736 (void) unlink (mac_new_name
);
738 return rename (mac_old_name
, mac_new_name
);
743 extern FILE *fopen (const char *name
, const char *mode
);
745 sys_fopen (const char *name
, const char *mode
)
747 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
749 char mac_pathname
[MAXPATHLEN
+1];
751 if (find_true_pathname (name
, true_pathname
, MAXPATHLEN
+1) == -1)
754 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
756 fully_resolved_name
[len
] = '\0';
758 strcpy (fully_resolved_name
, true_pathname
);
760 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
765 if (mode
[0] == 'w' || mode
[0] == 'a')
766 fsetfileinfo (mac_pathname
, 'EMAx', 'TEXT');
768 return fopen (mac_pathname
, mode
);
775 long target_ticks
= 0;
778 __sigfun alarm_signal_func
= (__sigfun
) 0;
780 __signal_func_ptr alarm_signal_func
= (__signal_func_ptr
) 0;
786 /* These functions simulate SIG_ALRM. The stub for function signal
787 stores the signal handler function in alarm_signal_func if a
788 SIG_ALRM is encountered. check_alarm is called in XTread_socket,
789 which emacs calls periodically. A pending alarm is represented by
790 a non-zero target_ticks value. check_alarm calls the handler
791 function pointed to by alarm_signal_func if one has been set up and
792 an alarm is pending. */
797 if (target_ticks
&& TickCount () > target_ticks
)
800 if (alarm_signal_func
)
801 (*alarm_signal_func
)(SIGALRM
);
807 select(n
, rfds
, wfds
, efds
, timeout
)
812 struct timeval
*timeout
;
814 EMACS_TIME end_time
, now
;
817 /* Can only handle wait for keyboard input. */
818 if (n
> 1 || wfds
|| efds
)
821 EMACS_GET_TIME (end_time
);
822 EMACS_ADD_TIME (end_time
, end_time
, *timeout
);
826 /* Also return true if an event other than a keyDown has
827 occurred. This causes kbd_buffer_get_event in keyboard.c to
828 call read_avail_input which in turn calls XTread_socket to
829 poll for these events. Otherwise these never get processed
830 except but a very slow poll timer. */
831 if (FD_ISSET (0, rfds
) && EventAvail (everyEvent
, &e
))
834 /* Also check movement of the mouse. */
837 static Point old_mouse_pos
= {-1, -1};
839 GetMouse (&mouse_pos
);
840 if (!EqualPt (mouse_pos
, old_mouse_pos
))
842 old_mouse_pos
= mouse_pos
;
847 WaitNextEvent (0, &e
, 1UL, NULL
); /* Accept no event; wait 1 tic. by T.I.*/
849 EMACS_GET_TIME (now
);
850 EMACS_SUB_TIME (now
, end_time
, now
);
852 while (!EMACS_TIME_NEG_P (now
));
858 /* Called in sys_select to wait for an alarm signal to arrive. */
866 if (!target_ticks
) /* no alarm pending */
869 if ( (tick
= TickCount ()) < target_ticks
)
870 WaitNextEvent (0, &e
, target_ticks
- tick
, NULL
); /* Accept no event; just wait. by T.I.*/
873 if (alarm_signal_func
)
874 (*alarm_signal_func
)(SIGALRM
);
883 long remaining
= target_ticks
? (TickCount () - target_ticks
) / 60 : 0;
885 target_ticks
= seconds
? TickCount () + 60 * seconds
: 0;
887 return (remaining
< 0) ? 0 : (unsigned int) remaining
;
893 extern __sigfun
signal (int signal
, __sigfun signal_func
);
895 sys_signal (int signal_num
, __sigfun signal_func
)
897 extern __signal_func_ptr
signal (int signal
, __signal_func_ptr signal_func
);
899 sys_signal (int signal_num
, __signal_func_ptr signal_func
)
904 if (signal_num
!= SIGALRM
)
905 return signal (signal_num
, signal_func
);
909 __sigfun old_signal_func
;
911 __signal_func_ptr old_signal_func
;
915 old_signal_func
= alarm_signal_func
;
916 alarm_signal_func
= signal_func
;
917 return old_signal_func
;
922 /* gettimeofday should return the amount of time (in a timeval
923 structure) since midnight today. The toolbox function Microseconds
924 returns the number of microseconds (in a UnsignedWide value) since
925 the machine was booted. Also making this complicated is WideAdd,
926 WideSubtract, etc. take wide values. */
933 static wide wall_clock_at_epoch
, clicks_at_epoch
;
934 UnsignedWide uw_microseconds
;
936 time_t sys_time (time_t *);
938 /* If this function is called for the first time, record the number
939 of seconds since midnight and the number of microseconds since
940 boot at the time of this first call. */
945 systime
= sys_time (NULL
);
946 /* Store microseconds since midnight in wall_clock_at_epoch. */
947 WideMultiply (systime
, 1000000L, &wall_clock_at_epoch
);
948 Microseconds (&uw_microseconds
);
949 /* Store microseconds since boot in clicks_at_epoch. */
950 clicks_at_epoch
.hi
= uw_microseconds
.hi
;
951 clicks_at_epoch
.lo
= uw_microseconds
.lo
;
954 /* Get time since boot */
955 Microseconds (&uw_microseconds
);
957 /* Convert to time since midnight*/
958 w_microseconds
.hi
= uw_microseconds
.hi
;
959 w_microseconds
.lo
= uw_microseconds
.lo
;
960 WideSubtract (&w_microseconds
, &clicks_at_epoch
);
961 WideAdd (&w_microseconds
, &wall_clock_at_epoch
);
962 tp
->tv_sec
= WideDivide (&w_microseconds
, 1000000L, &tp
->tv_usec
);
970 sleep (unsigned int seconds
)
972 unsigned long time_up
;
975 time_up
= TickCount () + seconds
* 60;
976 while (TickCount () < time_up
)
978 /* Accept no event; just wait. by T.I. */
979 WaitNextEvent (0, &e
, 30, NULL
);
987 /* The time functions adjust time values according to the difference
988 between the Unix and CW epoches. */
991 extern struct tm
*gmtime (const time_t *);
993 sys_gmtime (const time_t *timer
)
995 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
997 return gmtime (&unix_time
);
1002 extern struct tm
*localtime (const time_t *);
1004 sys_localtime (const time_t *timer
)
1006 #ifdef CODEWARRIOR_VERSION_6
1007 time_t unix_time
= *timer
;
1009 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
1012 return localtime (&unix_time
);
1017 extern char *ctime (const time_t *);
1019 sys_ctime (const time_t *timer
)
1021 #ifdef CODEWARRIOR_VERSION_6
1022 time_t unix_time
= *timer
;
1024 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
1027 return ctime (&unix_time
);
1032 extern time_t time (time_t *);
1034 sys_time (time_t *timer
)
1036 #ifdef CODEWARRIOR_VERSION_6
1037 time_t mac_time
= time (NULL
);
1039 time_t mac_time
= time (NULL
) - CW_OR_MPW_UNIX_EPOCH_DIFF
;
1049 /* MPW strftime broken for "%p" format */
1054 sys_strftime (char * s
, size_t maxsize
, const char * format
,
1055 const struct tm
* timeptr
)
1057 if (strcmp (format
, "%p") == 0)
1061 if (timeptr
->tm_hour
< 12)
1073 return strftime (s
, maxsize
, format
, timeptr
);
1075 #endif /* __MRC__ */
1078 /* no subprocesses, empty wait */
1088 croak (char *badfunc
)
1090 printf ("%s not yet implemented\r\n", badfunc
);
1096 index (const char * str
, int chr
)
1098 return strchr (str
, chr
);
1103 mktemp (char *template)
1108 len
= strlen (template);
1110 while (k
>= 0 && template[k
] == 'X')
1113 k
++; /* make k index of first 'X' */
1117 /* Zero filled, number of digits equal to the number of X's. */
1118 sprintf (&template[k
], "%0*d", len
-k
, seqnum
++);
1127 /* Emulate getpwuid, getpwnam and others. */
1129 #define PASSWD_FIELD_SIZE 256
1131 static char my_passwd_name
[PASSWD_FIELD_SIZE
];
1132 static char my_passwd_dir
[MAXPATHLEN
+1];
1134 static struct passwd my_passwd
=
1141 /* Initialized by main () in macterm.c to pathname of emacs directory. */
1143 char emacs_passwd_dir
[MAXPATHLEN
+1];
1149 init_emacs_passwd_dir ()
1153 if (getwd (emacs_passwd_dir
) && getwd (my_passwd_dir
))
1155 /* Need pathname of first ancestor that begins with "emacs"
1156 since Mac emacs application is somewhere in the emacs-*
1158 int len
= strlen (emacs_passwd_dir
);
1160 /* j points to the "/" following the directory name being
1163 while (i
>= 0 && !found
)
1165 while (i
>= 0 && emacs_passwd_dir
[i
] != '/')
1167 if (emacs_passwd_dir
[i
] == '/' && i
+5 < len
)
1168 found
= (strncmp (&(emacs_passwd_dir
[i
+1]), "emacs", 5) == 0);
1170 emacs_passwd_dir
[j
+1] = '\0';
1181 /* Setting to "/" probably won't work but set it to something
1183 strcpy (emacs_passwd_dir
, "/");
1184 strcpy (my_passwd_dir
, "/");
1189 static struct passwd emacs_passwd
=
1195 static int my_passwd_inited
= 0;
1203 /* Note: my_passwd_dir initialized in int_emacs_passwd_dir to
1204 directory where Emacs was started. */
1206 owner_name
= (char **) GetResource ('STR ',-16096);
1210 BlockMove ((unsigned char *) *owner_name
,
1211 (unsigned char *) my_passwd_name
,
1213 HUnlock (owner_name
);
1214 p2cstr ((unsigned char *) my_passwd_name
);
1217 my_passwd_name
[0] = 0;
1222 getpwuid (uid_t uid
)
1224 if (!my_passwd_inited
)
1227 my_passwd_inited
= 1;
1235 getpwnam (const char *name
)
1237 if (strcmp (name
, "emacs") == 0)
1238 return &emacs_passwd
;
1240 if (!my_passwd_inited
)
1243 my_passwd_inited
= 1;
1250 /* The functions fork, kill, sigsetmask, sigblock, request_sigio,
1251 setpgrp, setpriority, and unrequest_sigio are defined to be empty
1272 error ("Can't spawn subshell");
1291 request_sigio (void)
1297 unrequest_sigio (void)
1312 pipe (int _fildes
[2])
1319 /* Hard and symbolic links. */
1322 symlink (const char *name1
, const char *name2
)
1330 link (const char *name1
, const char *name2
)
1337 /* Determine the path name of the file specified by VREFNUM, DIRID,
1338 and NAME and place that in the buffer PATH of length
1341 path_from_vol_dir_name (char *path
, int man_path_len
, short vol_ref_num
,
1342 long dir_id
, ConstStr255Param name
)
1348 if (strlen (name
) > man_path_len
)
1351 memcpy (dir_name
, name
, name
[0]+1);
1352 memcpy (path
, name
, name
[0]+1);
1355 cipb
.dirInfo
.ioDrParID
= dir_id
;
1356 cipb
.dirInfo
.ioNamePtr
= dir_name
;
1360 cipb
.dirInfo
.ioVRefNum
= vol_ref_num
;
1361 cipb
.dirInfo
.ioFDirIndex
= -1;
1362 cipb
.dirInfo
.ioDrDirID
= cipb
.dirInfo
.ioDrParID
;
1363 /* go up to parent each time */
1365 err
= PBGetCatInfo (&cipb
, false);
1370 if (strlen (dir_name
) + strlen (path
) + 1 >= man_path_len
)
1373 strcat (dir_name
, ":");
1374 strcat (dir_name
, path
);
1375 /* attach to front since we're going up directory tree */
1376 strcpy (path
, dir_name
);
1378 while (cipb
.dirInfo
.ioDrDirID
!= fsRtDirID
);
1379 /* stop when we see the volume's root directory */
1381 return 1; /* success */
1386 readlink (const char *path
, char *buf
, int bufsiz
)
1388 char mac_sym_link_name
[MAXPATHLEN
+1];
1391 Boolean target_is_folder
, was_aliased
;
1392 Str255 directory_name
, mac_pathname
;
1395 if (posix_to_mac_pathname (path
, mac_sym_link_name
, MAXPATHLEN
+1) == 0)
1398 c2pstr (mac_sym_link_name
);
1399 err
= FSMakeFSSpec (0, 0, mac_sym_link_name
, &fsspec
);
1406 err
= ResolveAliasFile (&fsspec
, true, &target_is_folder
, &was_aliased
);
1407 if (err
!= noErr
|| !was_aliased
)
1413 if (path_from_vol_dir_name (mac_pathname
, 255, fsspec
.vRefNum
, fsspec
.parID
,
1420 if (mac_to_posix_pathname (mac_pathname
, buf
, bufsiz
) == 0)
1426 return strlen (buf
);
1430 /* Convert a path to one with aliases fully expanded. */
1433 find_true_pathname (const char *path
, char *buf
, int bufsiz
)
1435 char *q
, temp
[MAXPATHLEN
+1];
1439 if (bufsiz
<= 0 || path
== 0 || path
[0] == '\0')
1446 q
= strchr (p
+ 1, '/');
1448 q
= strchr (p
, '/');
1449 len
= 0; /* loop may not be entered, e.g., for "/" */
1454 strncat (temp
, p
, q
- p
);
1455 len
= readlink (temp
, buf
, bufsiz
);
1458 if (strlen (temp
) + 1 > bufsiz
)
1468 if (len
+ strlen (p
) + 1 >= bufsiz
)
1472 return len
+ strlen (p
);
1477 umask (mode_t numask
)
1479 static mode_t mask
= 022;
1480 mode_t oldmask
= mask
;
1487 chmod (const char *path
, mode_t mode
)
1489 /* say it always succeed for now */
1498 return fcntl (oldd
, F_DUPFD
, 0);
1500 /* current implementation of fcntl in fcntl.mac.c simply returns old
1502 return fcntl (oldd
, F_DUPFD
);
1509 /* This is from the original sysdep.c. Emulate BSD dup2. First close
1510 newd if it already exists. Then, attempt to dup oldd. If not
1511 successful, call dup2 recursively until we are, then close the
1512 unsuccessful ones. */
1515 dup2 (int oldd
, int newd
)
1526 ret
= dup2 (oldd
, newd
);
1532 /* let it fail for now */
1549 ioctl (int d
, int request
, void *argp
)
1559 if (fildes
>=0 && fildes
<= 2)
1592 #endif /* __MRC__ */
1596 #ifndef CODEWARRIOR_VERSION_6
1604 #endif /* __MWERKS__ */
1607 /* Return the path to the directory in which Emacs can create
1608 temporary files. The MacOS "temporary items" directory cannot be
1609 used because it removes the file written by a process when it
1610 exits. In that sense it's more like "/dev/null" than "/tmp" (but
1611 again not exactly). And of course Emacs needs to read back the
1612 files written by its subprocesses. So here we write the files to a
1613 directory "Emacs" in the Preferences Folder. This directory is
1614 created if it does not exist. */
1617 get_temp_dir_name ()
1619 static char *temp_dir_name
= NULL
;
1623 Str255 dir_name
, full_path
;
1625 char unix_dir_name
[MAXPATHLEN
+1];
1628 /* Cache directory name with pointer temp_dir_name.
1629 Look for it only the first time. */
1632 err
= FindFolder (kOnSystemDisk
, kPreferencesFolderType
, kCreateFolder
,
1633 &vol_ref_num
, &dir_id
);
1637 if (!path_from_vol_dir_name (full_path
, 255, vol_ref_num
, dir_id
, "\p"))
1640 if (strlen (full_path
) + 6 <= MAXPATHLEN
)
1641 strcat (full_path
, "Emacs:");
1645 if (!mac_to_posix_pathname (full_path
, unix_dir_name
, MAXPATHLEN
+1))
1648 dir
= opendir (unix_dir_name
); /* check whether temp directory exists */
1651 else if (mkdir (unix_dir_name
, 0700) != 0) /* create it if not */
1654 temp_dir_name
= (char *) malloc (strlen (unix_dir_name
) + 1);
1655 strcpy (temp_dir_name
, unix_dir_name
);
1658 return temp_dir_name
;
1662 /* Allocate and construct an array of pointers to strings from a list
1663 of strings stored in a 'STR#' resource. The returned pointer array
1664 is stored in the style of argv and environ: if the 'STR#' resource
1665 contains numString strings, an pointer array with numString+1
1666 elements is returned in which the last entry contains a null
1667 pointer. The pointer to the pointer array is passed by pointer in
1668 parameter t. The resource ID of the 'STR#' resource is passed in
1669 parameter StringListID.
1673 get_string_list (char ***t
, short string_list_id
)
1679 h
= GetResource ('STR#', string_list_id
);
1684 num_strings
= * (short *) p
;
1686 *t
= (char **) malloc (sizeof (char *) * (num_strings
+ 1));
1687 for (i
= 0; i
< num_strings
; i
++)
1689 short length
= *p
++;
1690 (*t
)[i
] = (char *) malloc (length
+ 1);
1691 strncpy ((*t
)[i
], p
, length
);
1692 (*t
)[i
][length
] = '\0';
1695 (*t
)[num_strings
] = 0;
1700 /* Return no string in case GetResource fails. Bug fixed by
1701 Ikegami Tsutomu. Caused MPW build to crash without sym -on
1702 option (no sym -on implies -opt local). */
1703 *t
= (char **) malloc (sizeof (char *));
1710 get_path_to_system_folder ()
1715 Str255 dir_name
, full_path
;
1717 static char system_folder_unix_name
[MAXPATHLEN
+1];
1720 err
= FindFolder (kOnSystemDisk
, kSystemFolderType
, kDontCreateFolder
,
1721 &vol_ref_num
, &dir_id
);
1725 if (!path_from_vol_dir_name (full_path
, 255, vol_ref_num
, dir_id
, "\p"))
1728 if (!mac_to_posix_pathname (full_path
, system_folder_unix_name
, MAXPATHLEN
+1))
1731 return system_folder_unix_name
;
1737 #define ENVIRON_STRING_LIST_ID 128
1739 /* Get environment variable definitions from STR# resource. */
1746 get_string_list (&environ
, ENVIRON_STRING_LIST_ID
);
1752 /* Make HOME directory the one Emacs starts up in if not specified
1754 if (getenv ("HOME") == NULL
)
1756 environ
= (char **) realloc (environ
, sizeof (char *) * (i
+ 2));
1759 environ
[i
] = (char *) malloc (strlen (my_passwd_dir
) + 6);
1762 strcpy (environ
[i
], "HOME=");
1763 strcat (environ
[i
], my_passwd_dir
);
1770 /* Make HOME directory the one Emacs starts up in if not specified
1772 if (getenv ("MAIL") == NULL
)
1774 environ
= (char **) realloc (environ
, sizeof (char *) * (i
+ 2));
1777 char * path_to_system_folder
= get_path_to_system_folder ();
1778 environ
[i
] = (char *) malloc (strlen (path_to_system_folder
) + 22);
1781 strcpy (environ
[i
], "MAIL=");
1782 strcat (environ
[i
], path_to_system_folder
);
1783 strcat (environ
[i
], "Eudora Folder/In");
1791 /* Return the value of the environment variable NAME. */
1794 getenv (const char *name
)
1796 int length
= strlen(name
);
1799 for (e
= environ
; *e
!= 0; e
++)
1800 if (strncmp(*e
, name
, length
) == 0 && (*e
)[length
] == '=')
1801 return &(*e
)[length
+ 1];
1803 if (strcmp (name
, "TMPDIR") == 0)
1804 return get_temp_dir_name ();
1811 /* see Interfaces&Libraries:Interfaces:CIncludes:signal.h */
1812 char *sys_siglist
[] =
1814 "Zero is not a signal!!!",
1816 "Interactive user interrupt", /* 2 */ "?",
1817 "Floating point exception", /* 4 */ "?", "?", "?",
1818 "Illegal instruction", /* 8 */ "?", "?", "?", "?", "?", "?", "?",
1819 "Segment violation", /* 16 */ "?", "?", "?", "?", "?", "?", "?",
1820 "?", "?", "?", "?", "?", "?", "?", "?",
1824 char *sys_siglist
[] =
1826 "Zero is not a signal!!!",
1828 "Floating point exception",
1829 "Illegal instruction",
1830 "Interactive user interrupt",
1831 "Segment violation",
1839 #include <utsname.h>
1842 uname (struct utsname
*name
)
1845 system_name
= GetString (-16413); /* IM - Resource Manager Reference */
1848 BlockMove (*system_name
, name
->nodename
, (*system_name
)[0]+1);
1849 p2cstr (name
->nodename
);
1857 #include <Processes.h>
1860 /* Event class of HLE sent to subprocess. */
1861 const OSType kEmacsSubprocessSend
= 'ESND';
1863 /* Event class of HLE sent back from subprocess. */
1864 const OSType kEmacsSubprocessReply
= 'ERPY';
1868 mystrchr (char *s
, char c
)
1870 while (*s
&& *s
!= c
)
1898 mystrcpy (char *to
, char *from
)
1910 /* Start a Mac subprocess. Arguments for it is passed in argv (null
1911 terminated). The process should run with the default directory
1912 "workdir", read input from "infn", and write output and error to
1913 "outfn" and "errfn", resp. The Process Manager call
1914 LaunchApplication is used to start the subprocess. We use high
1915 level events as the mechanism to pass arguments to the subprocess
1916 and to make Emacs wait for the subprocess to terminate and pass
1917 back a result code. The bulk of the code here packs the arguments
1918 into one message to be passed together with the high level event.
1919 Emacs also sometimes starts a subprocess using a shell to perform
1920 wildcard filename expansion. Since we don't really have a shell on
1921 the Mac, this case is detected and the starting of the shell is
1922 by-passed. We really need to add code here to do filename
1923 expansion to support such functionality. */
1926 run_mac_command (argv
, workdir
, infn
, outfn
, errfn
)
1927 unsigned char **argv
;
1928 const char *workdir
;
1929 const char *infn
, *outfn
, *errfn
;
1931 char macappname
[MAXPATHLEN
+1], macworkdir
[MAXPATHLEN
+1];
1932 char macinfn
[MAXPATHLEN
+1], macoutfn
[MAXPATHLEN
+1], macerrfn
[MAXPATHLEN
+1];
1933 int paramlen
, argc
, newargc
, j
, retries
;
1934 char **newargv
, *param
, *p
;
1937 LaunchParamBlockRec lpbr
;
1938 EventRecord send_event
, reply_event
;
1939 RgnHandle cursor_region_handle
;
1941 unsigned long ref_con
, len
;
1943 if (posix_to_mac_pathname (workdir
, macworkdir
, MAXPATHLEN
+1) == 0)
1945 if (posix_to_mac_pathname (infn
, macinfn
, MAXPATHLEN
+1) == 0)
1947 if (posix_to_mac_pathname (outfn
, macoutfn
, MAXPATHLEN
+1) == 0)
1949 if (posix_to_mac_pathname (errfn
, macerrfn
, MAXPATHLEN
+1) == 0)
1952 paramlen
= strlen (macworkdir
) + strlen (macinfn
) + strlen (macoutfn
)
1953 + strlen (macerrfn
) + 4; /* count nulls at end of strings */
1962 /* If a subprocess is invoked with a shell, we receive 3 arguments
1963 of the form: "<path to emacs bins>/sh" "-c" "<path to emacs
1964 bins>/<command> <command args>" */
1965 j
= strlen (argv
[0]);
1966 if (j
>= 3 && strcmp (argv
[0]+j
-3, "/sh") == 0
1967 && argc
== 3 && strcmp (argv
[1], "-c") == 0)
1969 char *command
, *t
, tempmacpathname
[MAXPATHLEN
+1];
1971 /* The arguments for the command in argv[2] are separated by
1972 spaces. Count them and put the count in newargc. */
1973 command
= (char *) alloca (strlen (argv
[2])+2);
1974 strcpy (command
, argv
[2]);
1975 if (command
[strlen (command
) - 1] != ' ')
1976 strcat (command
, " ");
1980 t
= mystrchr (t
, ' ');
1984 t
= mystrchr (t
+1, ' ');
1987 newargv
= (char **) alloca (sizeof (char *) * newargc
);
1990 for (j
= 0; j
< newargc
; j
++)
1992 newargv
[j
] = (char *) alloca (strlen (t
) + 1);
1993 mystrcpy (newargv
[j
], t
);
1996 paramlen
+= strlen (newargv
[j
]) + 1;
1999 if (strncmp (newargv
[0], "~emacs/", 7) == 0)
2001 if (posix_to_mac_pathname (newargv
[0], tempmacpathname
, MAXPATHLEN
+1)
2006 { /* sometimes Emacs call "sh" without a path for the command */
2008 char *t
= (char *) alloca (strlen (newargv
[0]) + 7 + 1);
2009 strcpy (t
, "~emacs/");
2010 strcat (t
, newargv
[0]);
2013 openp (Vexec_path
, build_string (newargv
[0]), Vexec_suffixes
, &path
,
2018 if (posix_to_mac_pathname (XSTRING (path
)->data
, tempmacpathname
,
2022 strcpy (macappname
, tempmacpathname
);
2026 if (posix_to_mac_pathname (argv
[0], macappname
, MAXPATHLEN
+1) == 0)
2029 newargv
= (char **) alloca (sizeof (char *) * argc
);
2031 for (j
= 1; j
< argc
; j
++)
2033 if (strncmp (argv
[j
], "~emacs/", 7) == 0)
2035 char *t
= strchr (argv
[j
], ' ');
2038 char tempcmdname
[MAXPATHLEN
+1], tempmaccmdname
[MAXPATHLEN
+1];
2039 strncpy (tempcmdname
, argv
[j
], t
-argv
[j
]);
2040 tempcmdname
[t
-argv
[j
]] = '\0';
2041 if (posix_to_mac_pathname (tempcmdname
, tempmaccmdname
,
2044 newargv
[j
] = (char *) alloca (strlen (tempmaccmdname
)
2046 strcpy (newargv
[j
], tempmaccmdname
);
2047 strcat (newargv
[j
], t
);
2051 char tempmaccmdname
[MAXPATHLEN
+1];
2052 if (posix_to_mac_pathname (argv
[j
], tempmaccmdname
,
2055 newargv
[j
] = (char *) alloca (strlen (tempmaccmdname
)+1);
2056 strcpy (newargv
[j
], tempmaccmdname
);
2060 newargv
[j
] = argv
[j
];
2061 paramlen
+= strlen (newargv
[j
]) + 1;
2065 /* After expanding all the arguments, we now know the length of the
2066 parameter block to be sent to the subprocess as a message
2067 attached to the HLE. */
2068 param
= (char *) malloc (paramlen
+ 1);
2074 /* first byte of message contains number of arguments for command */
2075 strcpy (p
, macworkdir
);
2076 p
+= strlen (macworkdir
);
2078 /* null terminate strings sent so it's possible to use strcpy over there */
2079 strcpy (p
, macinfn
);
2080 p
+= strlen (macinfn
);
2082 strcpy (p
, macoutfn
);
2083 p
+= strlen (macoutfn
);
2085 strcpy (p
, macerrfn
);
2086 p
+= strlen (macerrfn
);
2088 for (j
= 1; j
< newargc
; j
++)
2090 strcpy (p
, newargv
[j
]);
2091 p
+= strlen (newargv
[j
]);
2095 c2pstr (macappname
);
2097 iErr
= FSMakeFSSpec (0, 0, macappname
, &spec
);
2105 lpbr
.launchBlockID
= extendedBlock
;
2106 lpbr
.launchEPBLength
= extendedBlockLen
;
2107 lpbr
.launchControlFlags
= launchContinue
+ launchNoFileFlags
;
2108 lpbr
.launchAppSpec
= &spec
;
2109 lpbr
.launchAppParameters
= NULL
;
2111 iErr
= LaunchApplication (&lpbr
); /* call the subprocess */
2118 send_event
.what
= kHighLevelEvent
;
2119 send_event
.message
= kEmacsSubprocessSend
;
2120 /* Event ID stored in "where" unused */
2123 /* OS may think current subprocess has terminated if previous one
2124 terminated recently. */
2127 iErr
= PostHighLevelEvent (&send_event
, &lpbr
.launchProcessSN
, 0, param
,
2128 paramlen
+ 1, receiverIDisPSN
);
2130 while (iErr
== sessClosedErr
&& retries
-- > 0);
2138 cursor_region_handle
= NewRgn ();
2140 /* Wait for the subprocess to finish, when it will send us a ERPY
2141 high level event. */
2143 if (WaitNextEvent (highLevelEventMask
, &reply_event
, 180,
2144 cursor_region_handle
)
2145 && reply_event
.message
== kEmacsSubprocessReply
)
2148 /* The return code is sent through the refCon */
2149 iErr
= AcceptHighLevelEvent (&targ
, &ref_con
, NULL
, &len
);
2152 DisposeHandle ((Handle
) cursor_region_handle
);
2157 DisposeHandle ((Handle
) cursor_region_handle
);
2165 opendir (const char *dirname
)
2167 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
2168 char mac_pathname
[MAXPATHLEN
+1], vol_name
[MAXPATHLEN
+1];
2172 int len
, vol_name_len
;
2174 if (find_true_pathname (dirname
, true_pathname
, MAXPATHLEN
+1) == -1)
2177 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
2179 fully_resolved_name
[len
] = '\0';
2181 strcpy (fully_resolved_name
, true_pathname
);
2183 dirp
= (DIR *) malloc (sizeof(DIR));
2187 /* Handle special case when dirname is "/": sets up for readir to
2188 get all mount volumes. */
2189 if (strcmp (fully_resolved_name
, "/") == 0)
2191 dirp
->getting_volumes
= 1; /* special all mounted volumes DIR struct */
2192 dirp
->current_index
= 1; /* index for first volume */
2196 /* Handle typical cases: not accessing all mounted volumes. */
2197 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
2200 /* Emacs calls opendir without the trailing '/', Mac needs trailing ':' */
2201 len
= strlen (mac_pathname
);
2202 if (mac_pathname
[len
- 1] != ':' && len
< MAXPATHLEN
)
2203 strcat (mac_pathname
, ":");
2205 /* Extract volume name */
2206 vol_name_len
= strchr (mac_pathname
, ':') - mac_pathname
;
2207 strncpy (vol_name
, mac_pathname
, vol_name_len
);
2208 vol_name
[vol_name_len
] = '\0';
2209 strcat (vol_name
, ":");
2211 c2pstr (mac_pathname
);
2212 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
2213 /* using full pathname so vRefNum and DirID ignored */
2214 cipb
.hFileInfo
.ioVRefNum
= 0;
2215 cipb
.hFileInfo
.ioDirID
= 0;
2216 cipb
.hFileInfo
.ioFDirIndex
= 0;
2217 /* set to 0 to get information about specific dir or file */
2219 errno
= PBGetCatInfo (&cipb
, false);
2226 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x10)) /* bit 4 = 1 for directories */
2227 return 0; /* not a directory */
2229 dirp
->dir_id
= cipb
.dirInfo
.ioDrDirID
; /* used later in readdir */
2230 dirp
->getting_volumes
= 0;
2231 dirp
->current_index
= 1; /* index for first file/directory */
2234 vpb
.ioNamePtr
= vol_name
;
2235 /* using full pathname so vRefNum and DirID ignored */
2237 vpb
.ioVolIndex
= -1;
2238 errno
= PBHGetVInfo ((union HParamBlockRec
*) &vpb
, false);
2245 dirp
->vol_ref_num
= vpb
.ioVRefNum
;
2262 HParamBlockRec hpblock
;
2264 static struct dirent s_dirent
;
2265 static Str255 s_name
;
2269 /* Handle the root directory containing the mounted volumes. Call
2270 PBHGetVInfo specifying an index to obtain the info for a volume.
2271 PBHGetVInfo returns an error when it receives an index beyond the
2272 last volume, at which time we should return a nil dirent struct
2274 if (dp
->getting_volumes
)
2276 hpblock
.volumeParam
.ioNamePtr
= s_name
;
2277 hpblock
.volumeParam
.ioVRefNum
= 0;
2278 hpblock
.volumeParam
.ioVolIndex
= dp
->current_index
;
2280 errno
= PBHGetVInfo (&hpblock
, false);
2288 strcat (s_name
, "/"); /* need "/" for stat to work correctly */
2290 dp
->current_index
++;
2292 s_dirent
.d_ino
= hpblock
.volumeParam
.ioVRefNum
;
2293 s_dirent
.d_name
= s_name
;
2299 cipb
.hFileInfo
.ioVRefNum
= dp
->vol_ref_num
;
2300 cipb
.hFileInfo
.ioNamePtr
= s_name
;
2301 /* location to receive filename returned */
2303 /* return only visible files */
2307 cipb
.hFileInfo
.ioDirID
= dp
->dir_id
;
2308 /* directory ID found by opendir */
2309 cipb
.hFileInfo
.ioFDirIndex
= dp
->current_index
;
2311 errno
= PBGetCatInfo (&cipb
, false);
2318 /* insist on an visibile entry */
2319 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* directory? */
2320 done
= !(cipb
.dirInfo
.ioDrUsrWds
.frFlags
& fInvisible
);
2322 done
= !(cipb
.hFileInfo
.ioFlFndrInfo
.fdFlags
& fInvisible
);
2324 dp
->current_index
++;
2337 s_dirent
.d_ino
= cipb
.dirInfo
.ioDrDirID
;
2338 /* value unimportant: non-zero for valid file */
2339 s_dirent
.d_name
= s_name
;
2349 char mac_pathname
[MAXPATHLEN
+1];
2350 Str255 directory_name
;
2354 if (path_from_vol_dir_name (mac_pathname
, 255, 0, 0, "\p") == 0)
2357 if (mac_to_posix_pathname (mac_pathname
, path
, MAXPATHLEN
+1) == 0)
2365 initialize_applescript ()
2370 /* if open fails, as_scripting_component is set to NULL. Its
2371 subsequent use in OSA calls will fail with badComponentInstance
2373 as_scripting_component
= OpenDefaultComponent (kOSAComponentType
,
2374 kAppleScriptSubtype
);
2376 null_desc
.descriptorType
= typeNull
;
2377 null_desc
.dataHandle
= 0;
2378 osaerror
= OSAMakeContext (as_scripting_component
, &null_desc
,
2379 kOSANullScript
, &as_script_context
);
2381 as_script_context
= kOSANullScript
;
2382 /* use default context if create fails */
2386 void terminate_applescript()
2388 OSADispose (as_scripting_component
, as_script_context
);
2389 CloseComponent (as_scripting_component
);
2393 /* Compile and execute the AppleScript SCRIPT and return the error
2394 status as function value. A zero is returned if compilation and
2395 execution is successful, in which case RESULT returns a pointer to
2396 a string containing the resulting script value. Otherwise, the Mac
2397 error code is returned and RESULT returns a pointer to an error
2398 string. In both cases the caller should deallocate the storage
2399 used by the string pointed to by RESULT if it is non-NULL. For
2400 documentation on the MacOS scripting architecture, see Inside
2401 Macintosh - Interapplication Communications: Scripting Components. */
2404 do_applescript (char *script
, char **result
)
2406 AEDesc script_desc
, result_desc
, error_desc
;
2413 error
= AECreateDesc (typeChar
, script
, strlen(script
), &script_desc
);
2417 osaerror
= OSADoScript (as_scripting_component
, &script_desc
, kOSANullScript
,
2418 typeChar
, kOSAModeNull
, &result_desc
);
2420 if (osaerror
== errOSAScriptError
)
2422 /* error executing AppleScript: retrieve error message */
2423 if (!OSAScriptError (as_scripting_component
, kOSAErrorMessage
, typeChar
,
2426 HLock (error_desc
.dataHandle
);
2427 length
= GetHandleSize(error_desc
.dataHandle
);
2428 *result
= (char *) xmalloc (length
+ 1);
2431 memcpy (*result
, *(error_desc
.dataHandle
), length
);
2432 *(*result
+ length
) = '\0';
2434 HUnlock (error_desc
.dataHandle
);
2435 AEDisposeDesc (&error_desc
);
2438 else if (osaerror
== noErr
) /* success: retrieve resulting script value */
2440 HLock (result_desc
.dataHandle
);
2441 length
= GetHandleSize(result_desc
.dataHandle
);
2442 *result
= (char *) xmalloc (length
+ 1);
2445 memcpy (*result
, *(result_desc
.dataHandle
), length
);
2446 *(*result
+ length
) = '\0';
2448 HUnlock (result_desc
.dataHandle
);
2451 AEDisposeDesc (&script_desc
);
2452 AEDisposeDesc (&result_desc
);
2458 DEFUN ("do-applescript", Fdo_applescript
, Sdo_applescript
, 1, 1, 0,
2459 "Compile and execute AppleScript SCRIPT and retrieve and return the\n\
2460 result. If compilation and execution are successful, the resulting script\n\
2461 value is returned as a string. Otherwise the function aborts and\n\
2462 displays the error message returned by the AppleScript scripting\n\
2467 char *result
, *temp
;
2468 Lisp_Object lisp_result
;
2471 CHECK_STRING (script
, 0);
2473 status
= do_applescript (XSTRING (script
)->data
, &result
);
2477 error ("AppleScript error %ld", status
);
2480 /* Unfortunately only OSADoScript in do_applescript knows how
2481 how large the resulting script value or error message is
2482 going to be and therefore as caller memory must be
2483 deallocated here. It is necessary to free the error
2484 message before calling error to avoid a memory leak. */
2485 temp
= (char *) alloca (strlen (result
) + 1);
2486 strcpy (temp
, result
);
2493 lisp_result
= build_string (result
);
2500 DEFUN ("mac-file-name-to-posix", Fmac_file_name_to_posix
, Smac_file_name_to_posix
, 1,
2502 "Convert Macintosh filename to Posix form.")
2504 Lisp_Object mac_filename
;
2506 char posix_filename
[MAXPATHLEN
+1];
2508 CHECK_STRING (mac_filename
, 0);
2510 if (mac_to_posix_pathname (XSTRING (mac_filename
)->data
, posix_filename
,
2512 return build_string (posix_filename
);
2518 DEFUN ("posix-file-name-to-mac", Fposix_file_name_to_mac
, Sposix_file_name_to_mac
, 1,
2520 "Convert Unix filename to Mac form.")
2522 Lisp_Object posix_filename
;
2524 char mac_filename
[MAXPATHLEN
+1];
2526 CHECK_STRING (posix_filename
, 0);
2528 if (posix_to_mac_pathname (XSTRING (posix_filename
)->data
, mac_filename
,
2530 return build_string (mac_filename
);
2536 /* set interprogram-paste-function to mac-paste-function in mac-win.el
2537 to enable Emacs to obtain the contents of the Mac clipboard. */
2538 DEFUN ("mac-paste-function", Fmac_paste_function
, Smac_paste_function
, 0, 0, 0,
2539 "Return the contents of the Mac clipboard as a string.")
2544 long scrap_offset
, rc
, i
;
2546 my_handle
= NewHandle (0); /* allocate 0-length data area */
2548 rc
= GetScrap (my_handle
, 'TEXT', &scrap_offset
);
2554 /* Emacs expects clipboard contents have Unix-style eol's */
2555 for (i
= 0; i
< rc
; i
++)
2556 if ((*my_handle
)[i
] == '\r')
2557 (*my_handle
)[i
] = '\n';
2559 value
= make_string (*my_handle
, rc
);
2561 HUnlock (my_handle
);
2563 DisposeHandle (my_handle
);
2569 /* set interprogram-cut-function to mac-cut-function in mac-win.el
2570 to enable Emacs to write the top of the kill-ring to the Mac clipboard. */
2571 DEFUN ("mac-cut-function", Fmac_cut_function
, Smac_cut_function
, 1, 2, 0,
2572 "Put the value of the string parameter to the Mac clipboard.")
2574 Lisp_Object value
, push
;
2579 /* fixme: ignore the push flag for now */
2581 CHECK_STRING (value
, 0);
2583 len
= XSTRING (value
)->size
;
2584 buf
= (char *) alloca (len
);
2585 bcopy(XSTRING (value
)->data
, buf
, len
);
2587 /* convert to Mac-style eol's before sending to clipboard */
2588 for (i
= 0; i
< len
; i
++)
2593 PutScrap (len
, 'TEXT', buf
);
2599 DEFUN ("x-selection-exists-p", Fx_selection_exists_p
, Sx_selection_exists_p
,
2601 "Whether there is an owner for the given X Selection.\n\
2602 The arg should be the name of the selection in question, typically one of\n\
2603 the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.\n\
2604 \(Those are literal upper-case symbol names, since that's what X expects.)\n\
2605 For convenience, the symbol nil is the same as `PRIMARY',\n\
2606 and t is the same as `SECONDARY'.")
2608 Lisp_Object selection
;
2610 CHECK_SYMBOL (selection
, 0);
2612 /* Return nil for PRIMARY and SECONDARY selections; for CLIPBOARD, check
2613 if the clipboard currently has valid text format contents. */
2615 if (EQ (selection
, QCLIPBOARD
))
2617 Lisp_Object val
= Qnil
;
2620 long rc
, scrap_offset
;
2622 my_handle
= NewHandle (0);
2624 rc
= GetScrap (my_handle
, 'TEXT', &scrap_offset
);
2628 DisposeHandle (my_handle
);
2639 QCLIPBOARD
= intern ("CLIPBOARD");
2640 staticpro (&QCLIPBOARD
);
2642 defsubr (&Smac_paste_function
);
2643 defsubr (&Smac_cut_function
);
2644 defsubr (&Sx_selection_exists_p
);
2646 defsubr (&Sdo_applescript
);
2647 defsubr (&Smac_file_name_to_posix
);
2648 defsubr (&Sposix_file_name_to_mac
);