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_unix_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 unix_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 (unix_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_IFLNK
;
334 buf
->st_mode
&= ~S_IFREG
;
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)
373 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
376 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
379 fully_resolved_name
[len
] = '\0';
380 /* in fact our readlink terminates strings */
381 return lstat (fully_resolved_name
, sb
);
384 return lstat (true_pathname
, sb
);
389 /* CW defines fstat in stat.mac.c while MPW does not provide this
390 function. Without the information of how to get from a file
391 descriptor in MPW StdCLib to a Mac OS file spec, it should be hard
392 to implement this function. Fortunately, there is only one place
393 where this function is called in our configuration: in fileio.c,
394 where only the st_dev and st_ino fields are used to determine
395 whether two fildes point to different i-nodes to prevent copying
396 a file onto itself equal. What we have here probably needs
400 fstat (int fildes
, struct stat
*buf
)
403 buf
->st_ino
= fildes
;
404 buf
->st_mode
= S_IFREG
; /* added by T.I. for the copy-file */
405 return 0; /* success */
410 /* Adapted from Think Reference code example. */
413 mkdir (const char *dirname
, int mode
)
418 char true_pathname
[MAXPATHLEN
+1], mac_pathname
[MAXPATHLEN
+1];
420 if (find_true_pathname (dirname
, true_pathname
, MAXPATHLEN
+1) == -1)
423 if (unix_to_mac_pathname (true_pathname
, mac_pathname
, MAXPATHLEN
+1) == 0)
426 c2pstr (mac_pathname
);
427 hfpb
.ioNamePtr
= mac_pathname
;
428 hfpb
.ioVRefNum
= 0; /* ignored unless name is invalid */
429 hfpb
.ioDirID
= 0; /* parent is the root */
431 errno
= PBDirCreate ((HParmBlkPtr
) &hfpb
, false);
432 /* just return the Mac OSErr code for now */
433 return errno
== noErr
? 0 : -1;
438 sys_rmdir (const char *dirname
)
441 char mac_pathname
[MAXPATHLEN
+1];
443 if (unix_to_mac_pathname (dirname
, mac_pathname
, MAXPATHLEN
+1) == 0)
446 c2pstr (mac_pathname
);
447 hfpb
.ioNamePtr
= mac_pathname
;
448 hfpb
.ioVRefNum
= 0; /* ignored unless name is invalid */
449 hfpb
.ioDirID
= 0; /* parent is the root */
451 errno
= PBHDelete ((HParmBlkPtr
) &hfpb
, false);
452 return errno
== noErr
? 0 : -1;
457 /* No implementation yet. */
459 execvp (const char *path
, ...)
467 utime (const char *path
, const struct utimbuf
*times
)
469 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
471 char mac_pathname
[MAXPATHLEN
+1];
474 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
477 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
479 fully_resolved_name
[len
] = '\0';
481 strcpy (fully_resolved_name
, true_pathname
);
483 if (!unix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
486 c2pstr (mac_pathname
);
487 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
488 cipb
.hFileInfo
.ioVRefNum
= 0;
489 cipb
.hFileInfo
.ioDirID
= 0;
490 cipb
.hFileInfo
.ioFDirIndex
= 0;
491 /* set to 0 to get information about specific dir or file */
493 errno
= PBGetCatInfo (&cipb
, false);
497 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* bit 4 = 1 for directories */
500 cipb
.dirInfo
.ioDrMdDat
= times
->modtime
+ MAC_UNIX_EPOCH_DIFF
;
502 GetDateTime (&cipb
.dirInfo
.ioDrMdDat
);
507 cipb
.hFileInfo
.ioFlMdDat
= times
->modtime
+ MAC_UNIX_EPOCH_DIFF
;
509 GetDateTime (&cipb
.hFileInfo
.ioFlMdDat
);
512 errno
= PBSetCatInfo (&cipb
, false);
513 return errno
== noErr
? 0 : -1;
527 /* Like stat, but test for access mode in hfpb.ioFlAttrib */
529 access (const char *path
, int mode
)
531 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
533 char mac_pathname
[MAXPATHLEN
+1];
536 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
539 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
541 fully_resolved_name
[len
] = '\0';
543 strcpy (fully_resolved_name
, true_pathname
);
545 if (!unix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
548 c2pstr (mac_pathname
);
549 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
550 cipb
.hFileInfo
.ioVRefNum
= 0;
551 cipb
.hFileInfo
.ioDirID
= 0;
552 cipb
.hFileInfo
.ioFDirIndex
= 0;
553 /* set to 0 to get information about specific dir or file */
555 errno
= PBGetCatInfo (&cipb
, false);
559 if (mode
== F_OK
) /* got this far, file exists */
563 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* path refers to a directory */
567 if (cipb
.hFileInfo
.ioFlFndrInfo
.fdType
== 'APPL')
574 return (cipb
.hFileInfo
.ioFlAttrib
& 0x1) ? -1 : 0;
575 /* don't allow if lock bit is on */
581 #define DEV_NULL_FD 0x10000
585 sys_open (const char *path
, int oflag
)
587 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
589 char mac_pathname
[MAXPATHLEN
+1];
591 if (strcmp (path
, "/dev/null") == 0)
592 return DEV_NULL_FD
; /* some bogus fd to be ignored in write */
594 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
597 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
599 fully_resolved_name
[len
] = '\0';
601 strcpy (fully_resolved_name
, true_pathname
);
603 if (!unix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
608 if (oflag
== O_WRONLY
|| oflag
== O_RDWR
)
609 fsetfileinfo (mac_pathname
, 'EMAx', 'TEXT');
611 return open (mac_pathname
, oflag
);
618 sys_creat (const char *path
, mode_t mode
)
620 char true_pathname
[MAXPATHLEN
+1];
622 char mac_pathname
[MAXPATHLEN
+1];
624 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
627 if (!unix_to_mac_pathname (true_pathname
, mac_pathname
, MAXPATHLEN
+1))
632 int result
= creat (mac_pathname
);
633 fsetfileinfo (mac_pathname
, 'EMAx', 'TEXT');
636 return creat (mac_pathname
, mode
);
644 sys_unlink (const char *path
)
646 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
648 char mac_pathname
[MAXPATHLEN
+1];
650 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
653 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
655 fully_resolved_name
[len
] = '\0';
657 strcpy (fully_resolved_name
, true_pathname
);
659 if (!unix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
662 return unlink (mac_pathname
);
668 sys_read (int fildes
, char *buf
, int count
)
670 if (fildes
== 0) /* this should not be used for console input */
673 #ifdef CODEWARRIOR_VERSION_6
674 return _read (fildes
, buf
, count
);
676 return read (fildes
, buf
, count
);
683 sys_write (int fildes
, const char *buf
, int count
)
685 if (fildes
== DEV_NULL_FD
)
688 #ifdef CODEWARRIOR_VERSION_6
689 return _write (fildes
, buf
, count
);
691 return write (fildes
, buf
, count
);
698 sys_rename (const char * old_name
, const char * new_name
)
700 char true_old_pathname
[MAXPATHLEN
+1], true_new_pathname
[MAXPATHLEN
+1];
701 char fully_resolved_old_name
[MAXPATHLEN
+1];
703 char mac_old_name
[MAXPATHLEN
+1], mac_new_name
[MAXPATHLEN
+1];
705 if (find_true_pathname (old_name
, true_old_pathname
, MAXPATHLEN
+1) == -1)
708 len
= readlink (true_old_pathname
, fully_resolved_old_name
, MAXPATHLEN
);
710 fully_resolved_old_name
[len
] = '\0';
712 strcpy (fully_resolved_old_name
, true_old_pathname
);
714 if (find_true_pathname (new_name
, true_new_pathname
, MAXPATHLEN
+1) == -1)
717 if (strcmp (fully_resolved_old_name
, true_new_pathname
) == 0)
720 if (!unix_to_mac_pathname (fully_resolved_old_name
,
725 if (!unix_to_mac_pathname(true_new_pathname
, mac_new_name
, MAXPATHLEN
+1))
728 /* If a file with new_name already exists, rename deletes the old
729 file in Unix. CW version fails in these situation. So we add a
730 call to unlink here. */
731 (void) unlink (mac_new_name
);
733 return rename (mac_old_name
, mac_new_name
);
738 extern FILE *fopen (const char *name
, const char *mode
);
740 sys_fopen (const char *name
, const char *mode
)
742 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
744 char mac_pathname
[MAXPATHLEN
+1];
746 if (find_true_pathname (name
, true_pathname
, MAXPATHLEN
+1) == -1)
749 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
751 fully_resolved_name
[len
] = '\0';
753 strcpy (fully_resolved_name
, true_pathname
);
755 if (!unix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
760 if (mode
[0] == 'w' || mode
[0] == 'a')
761 fsetfileinfo (mac_pathname
, 'EMAx', 'TEXT');
763 return fopen (mac_pathname
, mode
);
770 long target_ticks
= 0;
773 __sigfun alarm_signal_func
= (__sigfun
) 0;
775 __signal_func_ptr alarm_signal_func
= (__signal_func_ptr
) 0;
781 /* These functions simulate SIG_ALRM. The stub for function signal
782 stores the signal handler function in alarm_signal_func if a
783 SIG_ALRM is encountered. check_alarm is called in XTread_socket,
784 which emacs calls periodically. A pending alarm is represented by
785 a non-zero target_ticks value. check_alarm calls the handler
786 function pointed to by alarm_signal_func if one has been set up and
787 an alarm is pending. */
792 if (target_ticks
&& TickCount () > target_ticks
)
795 if (alarm_signal_func
)
796 (*alarm_signal_func
)(SIGALRM
);
802 select(n
, rfds
, wfds
, efds
, timeout
)
807 struct timeval
*timeout
;
809 EMACS_TIME end_time
, now
;
811 unsigned long final_tick
;
813 /* Can only handle wait for keyboard input. */
814 if (n
> 1 || wfds
|| efds
)
817 EMACS_GET_TIME (end_time
);
818 EMACS_ADD_TIME (end_time
, end_time
, *timeout
);
822 /* Also return true if an event other than a keyDown has
823 occurred. This causes kbd_buffer_get_event in keyboard.c to
824 call read_avail_input which in turn calls XTread_socket to
825 poll for these events. Otherwise these never get processed
826 except but a very slow poll timer. */
827 if (FD_ISSET (0, rfds
) && EventAvail (everyEvent
, &e
))
830 /* Also check movement of the mouse. */
833 static Point old_mouse_pos
= {-1, -1};
835 GetMouse (&mouse_pos
);
836 if (!EqualPt (mouse_pos
, old_mouse_pos
))
838 old_mouse_pos
= mouse_pos
;
843 Delay (1UL, &final_tick
);
845 EMACS_GET_TIME (now
);
846 EMACS_SUB_TIME (now
, end_time
, now
);
848 while (!EMACS_TIME_NEG_P (now
));
854 /* Called in sys_select to wait for an alarm signal to arrive. */
859 unsigned long final_tick
;
861 if (!target_ticks
) /* no alarm pending */
864 while (TickCount () <= target_ticks
)
865 Delay (1UL, &final_tick
); /* wait 1/60 second before retrying */
868 if (alarm_signal_func
)
869 (*alarm_signal_func
)(SIGALRM
);
878 long remaining
= target_ticks
? (TickCount () - target_ticks
) / 60 : 0;
880 target_ticks
= seconds
? TickCount () + 60 * seconds
: 0;
882 return (remaining
< 0) ? 0 : (unsigned int) remaining
;
888 extern __sigfun
signal (int signal
, __sigfun signal_func
);
890 sys_signal (int signal_num
, __sigfun signal_func
)
892 extern __signal_func_ptr
signal (int signal
, __signal_func_ptr signal_func
);
894 sys_signal (int signal_num
, __signal_func_ptr signal_func
)
899 if (signal_num
!= SIGALRM
)
900 return signal (signal_num
, signal_func
);
904 __sigfun old_signal_func
;
906 __signal_func_ptr old_signal_func
;
910 old_signal_func
= alarm_signal_func
;
911 alarm_signal_func
= signal_func
;
912 return old_signal_func
;
917 /* gettimeofday should return the amount of time (in a timeval
918 structure) since midnight today. The toolbox function Microseconds
919 returns the number of microseconds (in a UnsignedWide value) since
920 the machine was booted. Also making this complicated is WideAdd,
921 WideSubtract, etc. take wide values. */
928 static wide wall_clock_at_epoch
, clicks_at_epoch
;
929 UnsignedWide uw_microseconds
;
931 time_t sys_time (time_t *);
933 /* If this function is called for the first time, record the number
934 of seconds since midnight and the number of microseconds since
935 boot at the time of this first call. */
940 systime
= sys_time (NULL
);
941 /* Store microseconds since midnight in wall_clock_at_epoch. */
942 WideMultiply (systime
, 1000000L, &wall_clock_at_epoch
);
943 Microseconds (&uw_microseconds
);
944 /* Store microseconds since boot in clicks_at_epoch. */
945 clicks_at_epoch
.hi
= uw_microseconds
.hi
;
946 clicks_at_epoch
.lo
= uw_microseconds
.lo
;
949 /* Get time since boot */
950 Microseconds (&uw_microseconds
);
952 /* Convert to time since midnight*/
953 w_microseconds
.hi
= uw_microseconds
.hi
;
954 w_microseconds
.lo
= uw_microseconds
.lo
;
955 WideSubtract (&w_microseconds
, &clicks_at_epoch
);
956 WideAdd (&w_microseconds
, &wall_clock_at_epoch
);
957 tp
->tv_sec
= WideDivide (&w_microseconds
, 1000000L, &tp
->tv_usec
);
965 sleep (unsigned int seconds
)
967 unsigned long final_tick
;
969 Delay (seconds
* 60UL, &final_tick
);
975 /* The time functions adjust time values according to the difference
976 between the Unix and CW epoches. */
979 extern struct tm
*gmtime (const time_t *);
981 sys_gmtime (const time_t *timer
)
983 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
985 return gmtime (&unix_time
);
990 extern struct tm
*localtime (const time_t *);
992 sys_localtime (const time_t *timer
)
994 #ifdef CODEWARRIOR_VERSION_6
995 time_t unix_time
= *timer
;
997 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
1000 return localtime (&unix_time
);
1005 extern char *ctime (const time_t *);
1007 sys_ctime (const time_t *timer
)
1009 #ifdef CODEWARRIOR_VERSION_6
1010 time_t unix_time
= *timer
;
1012 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
1015 return ctime (&unix_time
);
1020 extern time_t time (time_t *);
1022 sys_time (time_t *timer
)
1024 #ifdef CODEWARRIOR_VERSION_6
1025 time_t mac_time
= time (NULL
);
1027 time_t mac_time
= time (NULL
) - CW_OR_MPW_UNIX_EPOCH_DIFF
;
1037 /* MPW strftime broken for "%p" format */
1042 sys_strftime (char * s
, size_t maxsize
, const char * format
,
1043 const struct tm
* timeptr
)
1045 if (strcmp (format
, "%p") == 0)
1049 if (timeptr
->tm_hour
< 12)
1061 return strftime (s
, maxsize
, format
, timeptr
);
1063 #endif /* __MRC__ */
1066 /* no subprocesses, empty wait */
1076 croak (char *badfunc
)
1078 printf ("%s not yet implemented\r\n", badfunc
);
1084 index (const char * str
, int chr
)
1086 return strchr (str
, chr
);
1091 mktemp (char *template)
1096 len
= strlen (template);
1098 while (k
>= 0 && template[k
] == 'X')
1101 k
++; /* make k index of first 'X' */
1105 /* Zero filled, number of digits equal to the number of X's. */
1106 sprintf (&template[k
], "%0*d", len
-k
, seqnum
++);
1115 /* Emulate getpwuid, getpwnam and others. */
1117 #define PASSWD_FIELD_SIZE 256
1119 static char my_passwd_name
[PASSWD_FIELD_SIZE
];
1120 static char my_passwd_dir
[MAXPATHLEN
+1];
1122 static struct passwd my_passwd
=
1129 /* Initialized by main () in macterm.c to pathname of emacs directory. */
1131 char emacs_passwd_dir
[MAXPATHLEN
+1];
1137 init_emacs_passwd_dir ()
1141 if (getwd (emacs_passwd_dir
) && getwd (my_passwd_dir
))
1143 /* Need pathname of first ancestor that begins with "emacs"
1144 since Mac emacs application is somewhere in the emacs-*
1146 int len
= strlen (emacs_passwd_dir
);
1148 /* j points to the "/" following the directory name being
1151 while (i
>= 0 && !found
)
1153 while (i
>= 0 && emacs_passwd_dir
[i
] != '/')
1155 if (emacs_passwd_dir
[i
] == '/' && i
+5 < len
)
1156 found
= (strncmp (&(emacs_passwd_dir
[i
+1]), "emacs", 5) == 0);
1158 emacs_passwd_dir
[j
+1] = '\0';
1169 /* Setting to "/" probably won't work but set it to something
1171 strcpy (emacs_passwd_dir
, "/");
1172 strcpy (my_passwd_dir
, "/");
1177 static struct passwd emacs_passwd
=
1183 static int my_passwd_inited
= 0;
1191 /* Note: my_passwd_dir initialized in int_emacs_passwd_dir to
1192 directory where Emacs was started. */
1194 owner_name
= (char **) GetResource ('STR ',-16096);
1198 BlockMove ((unsigned char *) *owner_name
,
1199 (unsigned char *) my_passwd_name
,
1201 HUnlock (owner_name
);
1202 p2cstr ((unsigned char *) my_passwd_name
);
1205 my_passwd_name
[0] = 0;
1210 getpwuid (uid_t uid
)
1212 if (!my_passwd_inited
)
1215 my_passwd_inited
= 1;
1223 getpwnam (const char *name
)
1225 if (strcmp (name
, "emacs") == 0)
1226 return &emacs_passwd
;
1228 if (!my_passwd_inited
)
1231 my_passwd_inited
= 1;
1238 /* The functions fork, kill, sigsetmask, sigblock, request_sigio,
1239 setpgrp, setpriority, and unrequest_sigio are defined to be empty
1260 error ("Can't spawn subshell");
1279 request_sigio (void)
1285 unrequest_sigio (void)
1300 pipe (int _fildes
[2])
1307 /* Hard and symbolic links. */
1310 symlink (const char *name1
, const char *name2
)
1318 link (const char *name1
, const char *name2
)
1325 /* Determine the path name of the file specified by VREFNUM, DIRID,
1326 and NAME and place that in the buffer PATH of length
1329 path_from_vol_dir_name (char *path
, int man_path_len
, short vol_ref_num
,
1330 long dir_id
, ConstStr255Param name
)
1336 if (strlen (name
) > man_path_len
)
1339 memcpy (dir_name
, name
, name
[0]+1);
1340 memcpy (path
, name
, name
[0]+1);
1343 cipb
.dirInfo
.ioDrParID
= dir_id
;
1344 cipb
.dirInfo
.ioNamePtr
= dir_name
;
1348 cipb
.dirInfo
.ioVRefNum
= vol_ref_num
;
1349 cipb
.dirInfo
.ioFDirIndex
= -1;
1350 cipb
.dirInfo
.ioDrDirID
= cipb
.dirInfo
.ioDrParID
;
1351 /* go up to parent each time */
1353 err
= PBGetCatInfo (&cipb
, false);
1358 if (strlen (dir_name
) + strlen (path
) + 1 >= man_path_len
)
1361 strcat (dir_name
, ":");
1362 strcat (dir_name
, path
);
1363 /* attach to front since we're going up directory tree */
1364 strcpy (path
, dir_name
);
1366 while (cipb
.dirInfo
.ioDrDirID
!= fsRtDirID
);
1367 /* stop when we see the volume's root directory */
1369 return 1; /* success */
1374 readlink (const char *path
, char *buf
, int bufsiz
)
1376 char mac_sym_link_name
[MAXPATHLEN
+1];
1379 Boolean target_is_folder
, was_aliased
;
1380 Str255 directory_name
, mac_pathname
;
1383 if (unix_to_mac_pathname (path
, mac_sym_link_name
, MAXPATHLEN
+1) == 0)
1386 c2pstr (mac_sym_link_name
);
1387 err
= FSMakeFSSpec (0, 0, mac_sym_link_name
, &fsspec
);
1394 err
= ResolveAliasFile (&fsspec
, true, &target_is_folder
, &was_aliased
);
1395 if (err
!= noErr
|| !was_aliased
)
1401 if (path_from_vol_dir_name (mac_pathname
, 255, fsspec
.vRefNum
, fsspec
.parID
,
1408 if (mac_to_unix_pathname (mac_pathname
, buf
, bufsiz
) == 0)
1414 return strlen (buf
);
1418 /* Convert a path to one with aliases fully expanded. */
1421 find_true_pathname (const char *path
, char *buf
, int bufsiz
)
1423 char *q
, temp
[MAXPATHLEN
+1];
1427 if (bufsiz
<= 0 || path
== 0 || path
[0] == '\0')
1434 q
= strchr (p
+ 1, '/');
1436 q
= strchr (p
, '/');
1437 len
= 0; /* loop may not be entered, e.g., for "/" */
1442 strncat (temp
, p
, q
- p
);
1443 len
= readlink (temp
, buf
, bufsiz
);
1446 if (strlen (temp
) + 1 > bufsiz
)
1456 if (len
+ strlen (p
) + 1 >= bufsiz
)
1460 return len
+ strlen (p
);
1465 umask (mode_t numask
)
1467 static mode_t mask
= 022;
1468 mode_t oldmask
= mask
;
1475 chmod (const char *path
, mode_t mode
)
1477 /* say it always succeed for now */
1486 return fcntl (oldd
, F_DUPFD
, 0);
1488 /* current implementation of fcntl in fcntl.mac.c simply returns old
1490 return fcntl (oldd
, F_DUPFD
);
1497 /* This is from the original sysdep.c. Emulate BSD dup2. First close
1498 newd if it already exists. Then, attempt to dup oldd. If not
1499 successful, call dup2 recursively until we are, then close the
1500 unsuccessful ones. */
1503 dup2 (int oldd
, int newd
)
1514 ret
= dup2 (oldd
, newd
);
1520 /* let it fail for now */
1537 ioctl (int d
, int request
, void *argp
)
1547 if (fildes
>=0 && fildes
<= 2)
1580 #endif /* __MRC__ */
1584 #ifndef CODEWARRIOR_VERSION_6
1592 #endif /* __MWERKS__ */
1595 /* Return the path to the directory in which Emacs can create
1596 temporary files. The MacOS "temporary items" directory cannot be
1597 used because it removes the file written by a process when it
1598 exits. In that sense it's more like "/dev/null" than "/tmp" (but
1599 again not exactly). And of course Emacs needs to read back the
1600 files written by its subprocesses. So here we write the files to a
1601 directory "Emacs" in the Preferences Folder. This directory is
1602 created if it does not exist. */
1605 get_temp_dir_name ()
1607 static char *temp_dir_name
= NULL
;
1611 Str255 dir_name
, full_path
;
1613 char unix_dir_name
[MAXPATHLEN
+1];
1616 /* Cache directory name with pointer temp_dir_name.
1617 Look for it only the first time. */
1620 err
= FindFolder (kOnSystemDisk
, kPreferencesFolderType
, kCreateFolder
,
1621 &vol_ref_num
, &dir_id
);
1625 if (!path_from_vol_dir_name (full_path
, 255, vol_ref_num
, dir_id
, "\p"))
1628 if (strlen (full_path
) + 6 <= MAXPATHLEN
)
1629 strcat (full_path
, "Emacs:");
1633 if (!mac_to_unix_pathname (full_path
, unix_dir_name
, MAXPATHLEN
+1))
1636 dir
= opendir (unix_dir_name
); /* check whether temp directory exists */
1639 else if (mkdir (unix_dir_name
, 0700) != 0) /* create it if not */
1642 temp_dir_name
= (char *) malloc (strlen (unix_dir_name
) + 1);
1643 strcpy (temp_dir_name
, unix_dir_name
);
1646 return temp_dir_name
;
1650 /* Allocate and construct an array of pointers to strings from a list
1651 of strings stored in a 'STR#' resource. The returned pointer array
1652 is stored in the style of argv and environ: if the 'STR#' resource
1653 contains numString strings, an pointer array with numString+1
1654 elements is returned in which the last entry contains a null
1655 pointer. The pointer to the pointer array is passed by pointer in
1656 parameter t. The resource ID of the 'STR#' resource is passed in
1657 parameter StringListID.
1661 get_string_list (char ***t
, short string_list_id
)
1667 h
= GetResource ('STR#', string_list_id
);
1672 num_strings
= * (short *) p
;
1674 *t
= (char **) malloc (sizeof (char *) * (num_strings
+ 1));
1675 for (i
= 0; i
< num_strings
; i
++)
1677 short length
= *p
++;
1678 (*t
)[i
] = (char *) malloc (length
+ 1);
1679 strncpy ((*t
)[i
], p
, length
);
1680 (*t
)[i
][length
] = '\0';
1683 (*t
)[num_strings
] = 0;
1688 /* Return no string in case GetResource fails. Bug fixed by
1689 Ikegami Tsutomu. Caused MPW build to crash without sym -on
1690 option (no sym -on implies -opt local). */
1691 *t
= (char **) malloc (sizeof (char *));
1698 get_path_to_system_folder ()
1703 Str255 dir_name
, full_path
;
1705 static char system_folder_unix_name
[MAXPATHLEN
+1];
1708 err
= FindFolder (kOnSystemDisk
, kSystemFolderType
, kDontCreateFolder
,
1709 &vol_ref_num
, &dir_id
);
1713 if (!path_from_vol_dir_name (full_path
, 255, vol_ref_num
, dir_id
, "\p"))
1716 if (!mac_to_unix_pathname (full_path
, system_folder_unix_name
, MAXPATHLEN
+1))
1719 return system_folder_unix_name
;
1725 #define ENVIRON_STRING_LIST_ID 128
1727 /* Get environment variable definitions from STR# resource. */
1734 get_string_list (&environ
, ENVIRON_STRING_LIST_ID
);
1740 /* Make HOME directory the one Emacs starts up in if not specified
1742 if (getenv ("HOME") == NULL
)
1744 environ
= (char **) realloc (environ
, sizeof (char *) * (i
+ 2));
1747 environ
[i
] = (char *) malloc (strlen (my_passwd_dir
) + 6);
1750 strcpy (environ
[i
], "HOME=");
1751 strcat (environ
[i
], my_passwd_dir
);
1758 /* Make HOME directory the one Emacs starts up in if not specified
1760 if (getenv ("MAIL") == NULL
)
1762 environ
= (char **) realloc (environ
, sizeof (char *) * (i
+ 2));
1765 char * path_to_system_folder
= get_path_to_system_folder ();
1766 environ
[i
] = (char *) malloc (strlen (path_to_system_folder
) + 22);
1769 strcpy (environ
[i
], "MAIL=");
1770 strcat (environ
[i
], path_to_system_folder
);
1771 strcat (environ
[i
], "Eudora Folder/In");
1779 /* Return the value of the environment variable NAME. */
1782 getenv (const char *name
)
1784 int length
= strlen(name
);
1787 for (e
= environ
; *e
!= 0; e
++)
1788 if (strncmp(*e
, name
, length
) == 0 && (*e
)[length
] == '=')
1789 return &(*e
)[length
+ 1];
1791 if (strcmp (name
, "TMPDIR") == 0)
1792 return get_temp_dir_name ();
1799 /* see Interfaces&Libraries:Interfaces:CIncludes:signal.h */
1800 char *sys_siglist
[] =
1802 "Zero is not a signal!!!",
1804 "Interactive user interrupt", /* 2 */ "?",
1805 "Floating point exception", /* 4 */ "?", "?", "?",
1806 "Illegal instruction", /* 8 */ "?", "?", "?", "?", "?", "?", "?",
1807 "Segment violation", /* 16 */ "?", "?", "?", "?", "?", "?", "?",
1808 "?", "?", "?", "?", "?", "?", "?", "?",
1812 char *sys_siglist
[] =
1814 "Zero is not a signal!!!",
1816 "Floating point exception",
1817 "Illegal instruction",
1818 "Interactive user interrupt",
1819 "Segment violation",
1827 #include <utsname.h>
1830 uname (struct utsname
*name
)
1833 system_name
= GetString (-16413); /* IM - Resource Manager Reference */
1836 BlockMove (*system_name
, name
->nodename
, (*system_name
)[0]+1);
1837 p2cstr (name
->nodename
);
1845 #include <Processes.h>
1848 /* Event class of HLE sent to subprocess. */
1849 const OSType kEmacsSubprocessSend
= 'ESND';
1851 /* Event class of HLE sent back from subprocess. */
1852 const OSType kEmacsSubprocessReply
= 'ERPY';
1856 mystrchr (char *s
, char c
)
1858 while (*s
&& *s
!= c
)
1886 mystrcpy (char *to
, char *from
)
1898 /* Start a Mac subprocess. Arguments for it is passed in argv (null
1899 terminated). The process should run with the default directory
1900 "workdir", read input from "infn", and write output and error to
1901 "outfn" and "errfn", resp. The Process Manager call
1902 LaunchApplication is used to start the subprocess. We use high
1903 level events as the mechanism to pass arguments to the subprocess
1904 and to make Emacs wait for the subprocess to terminate and pass
1905 back a result code. The bulk of the code here packs the arguments
1906 into one message to be passed together with the high level event.
1907 Emacs also sometimes starts a subprocess using a shell to perform
1908 wildcard filename expansion. Since we don't really have a shell on
1909 the Mac, this case is detected and the starting of the shell is
1910 by-passed. We really need to add code here to do filename
1911 expansion to support such functionality. */
1914 run_mac_command (argv
, workdir
, infn
, outfn
, errfn
)
1915 unsigned char **argv
;
1916 const char *workdir
;
1917 const char *infn
, *outfn
, *errfn
;
1919 char macappname
[MAXPATHLEN
+1], macworkdir
[MAXPATHLEN
+1];
1920 char macinfn
[MAXPATHLEN
+1], macoutfn
[MAXPATHLEN
+1], macerrfn
[MAXPATHLEN
+1];
1921 int paramlen
, argc
, newargc
, j
, retries
;
1922 char **newargv
, *param
, *p
;
1925 LaunchParamBlockRec lpbr
;
1926 EventRecord send_event
, reply_event
;
1927 RgnHandle cursor_region_handle
;
1929 unsigned long ref_con
, len
;
1931 if (unix_to_mac_pathname (workdir
, macworkdir
, MAXPATHLEN
+1) == 0)
1933 if (unix_to_mac_pathname (infn
, macinfn
, MAXPATHLEN
+1) == 0)
1935 if (unix_to_mac_pathname (outfn
, macoutfn
, MAXPATHLEN
+1) == 0)
1937 if (unix_to_mac_pathname (errfn
, macerrfn
, MAXPATHLEN
+1) == 0)
1940 paramlen
= strlen (macworkdir
) + strlen (macinfn
) + strlen (macoutfn
)
1941 + strlen (macerrfn
) + 4; /* count nulls at end of strings */
1950 /* If a subprocess is invoked with a shell, we receive 3 arguments
1951 of the form: "<path to emacs bins>/sh" "-c" "<path to emacs
1952 bins>/<command> <command args>" */
1953 j
= strlen (argv
[0]);
1954 if (j
>= 3 && strcmp (argv
[0]+j
-3, "/sh") == 0
1955 && argc
== 3 && strcmp (argv
[1], "-c") == 0)
1957 char *command
, *t
, tempmacpathname
[MAXPATHLEN
+1];
1959 /* The arguments for the command in argv[2] are separated by
1960 spaces. Count them and put the count in newargc. */
1961 command
= (char *) alloca (strlen (argv
[2])+2);
1962 strcpy (command
, argv
[2]);
1963 if (command
[strlen (command
) - 1] != ' ')
1964 strcat (command
, " ");
1968 t
= mystrchr (t
, ' ');
1972 t
= mystrchr (t
+1, ' ');
1975 newargv
= (char **) alloca (sizeof (char *) * newargc
);
1978 for (j
= 0; j
< newargc
; j
++)
1980 newargv
[j
] = (char *) alloca (strlen (t
) + 1);
1981 mystrcpy (newargv
[j
], t
);
1984 paramlen
+= strlen (newargv
[j
]) + 1;
1987 if (strncmp (newargv
[0], "~emacs/", 7) == 0)
1989 if (unix_to_mac_pathname (newargv
[0], tempmacpathname
, MAXPATHLEN
+1)
1994 { /* sometimes Emacs call "sh" without a path for the command */
1996 char *t
= (char *) alloca (strlen (newargv
[0]) + 7 + 1);
1997 strcpy (t
, "~emacs/");
1998 strcat (t
, newargv
[0]);
2001 openp (Vexec_path
, build_string (newargv
[0]), EXEC_SUFFIXES
, &path
,
2006 if (unix_to_mac_pathname (XSTRING (path
)->data
, tempmacpathname
,
2010 strcpy (macappname
, tempmacpathname
);
2014 if (unix_to_mac_pathname (argv
[0], macappname
, MAXPATHLEN
+1) == 0)
2017 newargv
= (char **) alloca (sizeof (char *) * argc
);
2019 for (j
= 1; j
< argc
; j
++)
2021 if (strncmp (argv
[j
], "~emacs/", 7) == 0)
2023 char *t
= strchr (argv
[j
], ' ');
2026 char tempcmdname
[MAXPATHLEN
+1], tempmaccmdname
[MAXPATHLEN
+1];
2027 strncpy (tempcmdname
, argv
[j
], t
-argv
[j
]);
2028 tempcmdname
[t
-argv
[j
]] = '\0';
2029 if (unix_to_mac_pathname (tempcmdname
, tempmaccmdname
,
2032 newargv
[j
] = (char *) alloca (strlen (tempmaccmdname
)
2034 strcpy (newargv
[j
], tempmaccmdname
);
2035 strcat (newargv
[j
], t
);
2039 char tempmaccmdname
[MAXPATHLEN
+1];
2040 if (unix_to_mac_pathname (argv
[j
], tempmaccmdname
,
2043 newargv
[j
] = (char *) alloca (strlen (tempmaccmdname
)+1);
2044 strcpy (newargv
[j
], tempmaccmdname
);
2048 newargv
[j
] = argv
[j
];
2049 paramlen
+= strlen (newargv
[j
]) + 1;
2053 /* After expanding all the arguments, we now know the length of the
2054 parameter block to be sent to the subprocess as a message
2055 attached to the HLE. */
2056 param
= (char *) malloc (paramlen
+ 1);
2062 /* first byte of message contains number of arguments for command */
2063 strcpy (p
, macworkdir
);
2064 p
+= strlen (macworkdir
);
2066 /* null terminate strings sent so it's possible to use strcpy over there */
2067 strcpy (p
, macinfn
);
2068 p
+= strlen (macinfn
);
2070 strcpy (p
, macoutfn
);
2071 p
+= strlen (macoutfn
);
2073 strcpy (p
, macerrfn
);
2074 p
+= strlen (macerrfn
);
2076 for (j
= 1; j
< newargc
; j
++)
2078 strcpy (p
, newargv
[j
]);
2079 p
+= strlen (newargv
[j
]);
2083 c2pstr (macappname
);
2085 iErr
= FSMakeFSSpec (0, 0, macappname
, &spec
);
2093 lpbr
.launchBlockID
= extendedBlock
;
2094 lpbr
.launchEPBLength
= extendedBlockLen
;
2095 lpbr
.launchControlFlags
= launchContinue
+ launchNoFileFlags
;
2096 lpbr
.launchAppSpec
= &spec
;
2097 lpbr
.launchAppParameters
= NULL
;
2099 iErr
= LaunchApplication (&lpbr
); /* call the subprocess */
2106 send_event
.what
= kHighLevelEvent
;
2107 send_event
.message
= kEmacsSubprocessSend
;
2108 /* Event ID stored in "where" unused */
2111 /* OS may think current subprocess has terminated if previous one
2112 terminated recently. */
2115 iErr
= PostHighLevelEvent (&send_event
, &lpbr
.launchProcessSN
, 0, param
,
2116 paramlen
+ 1, receiverIDisPSN
);
2118 while (iErr
== sessClosedErr
&& retries
-- > 0);
2126 cursor_region_handle
= NewRgn ();
2128 /* Wait for the subprocess to finish, when it will send us a ERPY
2129 high level event. */
2131 if (WaitNextEvent (highLevelEventMask
, &reply_event
, 180,
2132 cursor_region_handle
)
2133 && reply_event
.message
== kEmacsSubprocessReply
)
2136 /* The return code is sent through the refCon */
2137 iErr
= AcceptHighLevelEvent (&targ
, &ref_con
, NULL
, &len
);
2140 DisposeHandle ((Handle
) cursor_region_handle
);
2145 DisposeHandle ((Handle
) cursor_region_handle
);
2153 opendir (const char *dirname
)
2155 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
2156 char mac_pathname
[MAXPATHLEN
+1], vol_name
[MAXPATHLEN
+1];
2160 int len
, vol_name_len
;
2162 if (find_true_pathname (dirname
, true_pathname
, MAXPATHLEN
+1) == -1)
2165 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
2167 fully_resolved_name
[len
] = '\0';
2169 strcpy (fully_resolved_name
, true_pathname
);
2171 dirp
= (DIR *) malloc (sizeof(DIR));
2175 /* Handle special case when dirname is "/": sets up for readir to
2176 get all mount volumes. */
2177 if (strcmp (fully_resolved_name
, "/") == 0)
2179 dirp
->getting_volumes
= 1; /* special all mounted volumes DIR struct */
2180 dirp
->current_index
= 1; /* index for first volume */
2184 /* Handle typical cases: not accessing all mounted volumes. */
2185 if (!unix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
2188 /* Emacs calls opendir without the trailing '/', Mac needs trailing ':' */
2189 len
= strlen (mac_pathname
);
2190 if (mac_pathname
[len
- 1] != ':' && len
< MAXPATHLEN
)
2191 strcat (mac_pathname
, ":");
2193 /* Extract volume name */
2194 vol_name_len
= strchr (mac_pathname
, ':') - mac_pathname
;
2195 strncpy (vol_name
, mac_pathname
, vol_name_len
);
2196 vol_name
[vol_name_len
] = '\0';
2197 strcat (vol_name
, ":");
2199 c2pstr (mac_pathname
);
2200 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
2201 /* using full pathname so vRefNum and DirID ignored */
2202 cipb
.hFileInfo
.ioVRefNum
= 0;
2203 cipb
.hFileInfo
.ioDirID
= 0;
2204 cipb
.hFileInfo
.ioFDirIndex
= 0;
2205 /* set to 0 to get information about specific dir or file */
2207 errno
= PBGetCatInfo (&cipb
, false);
2214 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x10)) /* bit 4 = 1 for directories */
2215 return 0; /* not a directory */
2217 dirp
->dir_id
= cipb
.dirInfo
.ioDrDirID
; /* used later in readdir */
2218 dirp
->getting_volumes
= 0;
2219 dirp
->current_index
= 1; /* index for first file/directory */
2222 vpb
.ioNamePtr
= vol_name
;
2223 /* using full pathname so vRefNum and DirID ignored */
2225 vpb
.ioVolIndex
= -1;
2226 errno
= PBHGetVInfo ((union HParamBlockRec
*) &vpb
, false);
2233 dirp
->vol_ref_num
= vpb
.ioVRefNum
;
2250 HParamBlockRec hpblock
;
2252 static struct dirent s_dirent
;
2253 static Str255 s_name
;
2257 /* Handle the root directory containing the mounted volumes. Call
2258 PBHGetVInfo specifying an index to obtain the info for a volume.
2259 PBHGetVInfo returns an error when it receives an index beyond the
2260 last volume, at which time we should return a nil dirent struct
2262 if (dp
->getting_volumes
)
2264 hpblock
.volumeParam
.ioNamePtr
= s_name
;
2265 hpblock
.volumeParam
.ioVRefNum
= 0;
2266 hpblock
.volumeParam
.ioVolIndex
= dp
->current_index
;
2268 errno
= PBHGetVInfo (&hpblock
, false);
2276 strcat (s_name
, "/"); /* need "/" for stat to work correctly */
2278 dp
->current_index
++;
2280 s_dirent
.d_ino
= hpblock
.volumeParam
.ioVRefNum
;
2281 s_dirent
.d_name
= s_name
;
2287 cipb
.hFileInfo
.ioVRefNum
= dp
->vol_ref_num
;
2288 cipb
.hFileInfo
.ioNamePtr
= s_name
;
2289 /* location to receive filename returned */
2291 /* return only visible files */
2295 cipb
.hFileInfo
.ioDirID
= dp
->dir_id
;
2296 /* directory ID found by opendir */
2297 cipb
.hFileInfo
.ioFDirIndex
= dp
->current_index
;
2299 errno
= PBGetCatInfo (&cipb
, false);
2306 /* insist on an visibile entry */
2307 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* directory? */
2308 done
= !(cipb
.dirInfo
.ioDrUsrWds
.frFlags
& fInvisible
);
2310 done
= !(cipb
.hFileInfo
.ioFlFndrInfo
.fdFlags
& fInvisible
);
2312 dp
->current_index
++;
2325 s_dirent
.d_ino
= cipb
.dirInfo
.ioDrDirID
;
2326 /* value unimportant: non-zero for valid file */
2327 s_dirent
.d_name
= s_name
;
2337 char mac_pathname
[MAXPATHLEN
+1];
2338 Str255 directory_name
;
2342 if (path_from_vol_dir_name (mac_pathname
, 255, 0, 0, "\p") == 0)
2345 if (mac_to_unix_pathname (mac_pathname
, path
, MAXPATHLEN
+1) == 0)
2353 initialize_applescript ()
2358 /* if open fails, as_scripting_component is set to NULL. Its
2359 subsequent use in OSA calls will fail with badComponentInstance
2361 as_scripting_component
= OpenDefaultComponent (kOSAComponentType
,
2362 kAppleScriptSubtype
);
2364 null_desc
.descriptorType
= typeNull
;
2365 null_desc
.dataHandle
= 0;
2366 osaerror
= OSAMakeContext (as_scripting_component
, &null_desc
,
2367 kOSANullScript
, &as_script_context
);
2369 as_script_context
= kOSANullScript
;
2370 /* use default context if create fails */
2374 void terminate_applescript()
2376 OSADispose (as_scripting_component
, as_script_context
);
2377 CloseComponent (as_scripting_component
);
2381 /* Compile and execute the AppleScript SCRIPT and return the error
2382 status as function value. A zero is returned if compilation and
2383 execution is successful, in which case RESULT returns a pointer to
2384 a string containing the resulting script value. Otherwise, the Mac
2385 error code is returned and RESULT returns a pointer to an error
2386 string. In both cases the caller should deallocate the storage
2387 used by the string pointed to by RESULT if it is non-NULL. For
2388 documentation on the MacOS scripting architecture, see Inside
2389 Macintosh - Interapplication Communications: Scripting Components. */
2392 do_applescript (char *script
, char **result
)
2394 AEDesc script_desc
, result_desc
, error_desc
;
2401 error
= AECreateDesc (typeChar
, script
, strlen(script
), &script_desc
);
2405 osaerror
= OSADoScript (as_scripting_component
, &script_desc
, kOSANullScript
,
2406 typeChar
, kOSAModeNull
, &result_desc
);
2408 if (osaerror
== errOSAScriptError
)
2410 /* error executing AppleScript: retrieve error message */
2411 if (!OSAScriptError (as_scripting_component
, kOSAErrorMessage
, typeChar
,
2414 HLock (error_desc
.dataHandle
);
2415 length
= GetHandleSize(error_desc
.dataHandle
);
2416 *result
= (char *) xmalloc (length
+ 1);
2419 memcpy (*result
, *(error_desc
.dataHandle
), length
);
2420 *(*result
+ length
) = '\0';
2422 HUnlock (error_desc
.dataHandle
);
2423 AEDisposeDesc (&error_desc
);
2426 else if (osaerror
== noErr
) /* success: retrieve resulting script value */
2428 HLock (result_desc
.dataHandle
);
2429 length
= GetHandleSize(result_desc
.dataHandle
);
2430 *result
= (char *) xmalloc (length
+ 1);
2433 memcpy (*result
, *(result_desc
.dataHandle
), length
);
2434 *(*result
+ length
) = '\0';
2436 HUnlock (result_desc
.dataHandle
);
2439 AEDisposeDesc (&script_desc
);
2440 AEDisposeDesc (&result_desc
);
2446 DEFUN ("do-applescript", Fdo_applescript
, Sdo_applescript
, 1, 1, 0,
2447 "Compile and execute AppleScript SCRIPT and retrieve and return the\n\
2448 result. If compilation and execution are successful, the resulting script\n\
2449 value is returned as a string. Otherwise the function aborts and\n\
2450 displays the error message returned by the AppleScript scripting\n\
2455 char *result
, *temp
;
2456 Lisp_Object lisp_result
;
2459 CHECK_STRING (script
, 0);
2461 status
= do_applescript (XSTRING (script
)->data
, &result
);
2465 error ("AppleScript error %ld", status
);
2468 /* Unfortunately only OSADoScript in do_applescript knows how
2469 how large the resulting script value or error message is
2470 going to be and therefore as caller memory must be
2471 deallocated here. It is necessary to free the error
2472 message before calling error to avoid a memory leak. */
2473 temp
= (char *) alloca (strlen (result
) + 1);
2474 strcpy (temp
, result
);
2481 lisp_result
= build_string (result
);
2488 DEFUN ("mac-filename-to-unix", Fmac_filename_to_unix
, Smac_filename_to_unix
, 1,
2490 "Convert Macintosh filename to Unix form.")
2492 Lisp_Object mac_filename
;
2494 char unix_filename
[MAXPATHLEN
+1];
2496 CHECK_STRING (mac_filename
, 0);
2498 if (mac_to_unix_pathname(XSTRING (mac_filename
)->data
, unix_filename
,
2500 return build_string (unix_filename
);
2506 DEFUN ("unix-filename-to-mac", Funix_filename_to_mac
, Sunix_filename_to_mac
, 1,
2508 "Convert Unix filename to Mac form.")
2510 Lisp_Object unix_filename
;
2512 char mac_filename
[MAXPATHLEN
+1];
2514 CHECK_STRING (unix_filename
, 0);
2516 if (unix_to_mac_pathname(XSTRING (unix_filename
)->data
, mac_filename
,
2518 return build_string (mac_filename
);
2524 /* set interprogram-paste-function to mac-paste-function in mac-win.el
2525 to enable Emacs to obtain the contents of the Mac clipboard. */
2526 DEFUN ("mac-paste-function", Fmac_paste_function
, Smac_paste_function
, 0, 0, 0,
2527 "Return the contents of the Mac clipboard as a string.")
2532 long scrap_offset
, rc
, i
;
2534 my_handle
= NewHandle (0); /* allocate 0-length data area */
2536 rc
= GetScrap (my_handle
, 'TEXT', &scrap_offset
);
2542 /* Emacs expects clipboard contents have Unix-style eol's */
2543 for (i
= 0; i
< rc
; i
++)
2544 if ((*my_handle
)[i
] == '\r')
2545 (*my_handle
)[i
] = '\n';
2547 value
= make_string (*my_handle
, rc
);
2549 HUnlock (my_handle
);
2551 DisposeHandle (my_handle
);
2557 /* set interprogram-cut-function to mac-cut-function in mac-win.el
2558 to enable Emacs to write the top of the kill-ring to the Mac clipboard. */
2559 DEFUN ("mac-cut-function", Fmac_cut_function
, Smac_cut_function
, 1, 2, 0,
2560 "Put the value of the string parameter to the Mac clipboard.")
2562 Lisp_Object value
, push
;
2567 /* fixme: ignore the push flag for now */
2569 CHECK_STRING (value
, 0);
2571 len
= XSTRING (value
)->size
;
2572 buf
= (char *) alloca (len
);
2573 bcopy(XSTRING (value
)->data
, buf
, len
);
2575 /* convert to Mac-style eol's before sending to clipboard */
2576 for (i
= 0; i
< len
; i
++)
2581 PutScrap (len
, 'TEXT', buf
);
2587 DEFUN ("x-selection-exists-p", Fx_selection_exists_p
, Sx_selection_exists_p
,
2589 "Whether there is an owner for the given X Selection.\n\
2590 The arg should be the name of the selection in question, typically one of\n\
2591 the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.\n\
2592 \(Those are literal upper-case symbol names, since that's what X expects.)\n\
2593 For convenience, the symbol nil is the same as `PRIMARY',\n\
2594 and t is the same as `SECONDARY'.")
2596 Lisp_Object selection
;
2598 CHECK_SYMBOL (selection
, 0);
2600 /* Return nil for PRIMARY and SECONDARY selections; for CLIPBOARD, check
2601 if the clipboard currently has valid text format contents. */
2603 if (EQ (selection
, QCLIPBOARD
))
2605 Lisp_Object val
= Qnil
;
2608 long rc
, scrap_offset
;
2610 my_handle
= NewHandle (0);
2612 rc
= GetScrap (my_handle
, 'TEXT', &scrap_offset
);
2616 DisposeHandle (my_handle
);
2627 QCLIPBOARD
= intern ("CLIPBOARD");
2628 staticpro (&QCLIPBOARD
);
2630 defsubr (&Smac_paste_function
);
2631 defsubr (&Smac_cut_function
);
2632 defsubr (&Sx_selection_exists_p
);
2634 defsubr (&Sdo_applescript
);
2635 defsubr (&Smac_filename_to_unix
);
2636 defsubr (&Sunix_filename_to_mac
);