(gnus-summary-mode-map): Map follow-link to mouse-face.
[emacs.git] / src / mac.c
blob53e56cfb54176766d7d3a6f98e341d4a82107272
1 /* Unix emulation routines for GNU Emacs on the Mac OS.
2 Copyright (C) 2000, 2001 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 /* Contributed by Andrew Choi (akochoi@mac.com). */
23 #include <config.h>
25 #include <stdio.h>
26 #include <errno.h>
27 #include <time.h>
28 #include <utime.h>
29 #include <dirent.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <string.h>
33 #include <pwd.h>
34 #include <grp.h>
35 #include <sys/param.h>
36 #include <stdlib.h>
37 #include <fcntl.h>
38 #if __MWERKS__
39 #include <unistd.h>
40 #endif
42 #ifdef MAC_OSX
43 #undef mktime
44 #undef DEBUG
45 #undef free
46 #undef malloc
47 #undef realloc
48 #undef init_process
49 #include <Carbon/Carbon.h>
50 #undef mktime
51 #define mktime emacs_mktime
52 #undef free
53 #define free unexec_free
54 #undef malloc
55 #define malloc unexec_malloc
56 #undef realloc
57 #define realloc unexec_realloc
58 #undef init_process
59 #define init_process emacs_init_process
60 #else /* not MAC_OSX */
61 #include <Files.h>
62 #include <MacTypes.h>
63 #include <TextUtils.h>
64 #include <Folders.h>
65 #include <Resources.h>
66 #include <Aliases.h>
67 #include <FixMath.h>
68 #include <Timer.h>
69 #include <OSA.h>
70 #include <AppleScript.h>
71 #include <Scrap.h>
72 #endif /* not MAC_OSX */
74 #include "lisp.h"
75 #include "process.h"
76 #include "sysselect.h"
77 #include "systime.h"
78 #include "blockinput.h"
80 Lisp_Object QCLIPBOARD;
82 /* An instance of the AppleScript component. */
83 static ComponentInstance as_scripting_component;
84 /* The single script context used for all script executions. */
85 static OSAID as_script_context;
88 /* When converting from Mac to Unix pathnames, /'s in folder names are
89 converted to :'s. This function, used in copying folder names,
90 performs a strncat and converts all character a to b in the copy of
91 the string s2 appended to the end of s1. */
93 void
94 string_cat_and_replace (char *s1, const char *s2, int n, char a, char b)
96 int l1 = strlen (s1);
97 int l2 = strlen (s2);
98 char *p = s1 + l1;
99 int i;
101 strncat (s1, s2, n);
102 for (i = 0; i < l2; i++)
104 if (*p == a)
105 *p = b;
106 p++;
111 /* Convert a Mac pathname to Posix form. A Mac full pathname is one
112 that does not begin with a ':' and contains at least one ':'. A Mac
113 full pathname causes a '/' to be prepended to the Posix pathname.
114 The algorithm for the rest of the pathname is as follows:
115 For each segment between two ':',
116 if it is non-null, copy as is and then add a '/' at the end,
117 otherwise, insert a "../" into the Posix pathname.
118 Returns 1 if successful; 0 if fails. */
121 mac_to_posix_pathname (const char *mfn, char *ufn, int ufnbuflen)
123 const char *p, *q, *pe;
125 strcpy (ufn, "");
127 if (*mfn == '\0')
128 return 1;
130 p = strchr (mfn, ':');
131 if (p != 0 && p != mfn) /* full pathname */
132 strcat (ufn, "/");
134 p = mfn;
135 if (*p == ':')
136 p++;
138 pe = mfn + strlen (mfn);
139 while (p < pe)
141 q = strchr (p, ':');
142 if (q)
144 if (q == p)
145 { /* two consecutive ':' */
146 if (strlen (ufn) + 3 >= ufnbuflen)
147 return 0;
148 strcat (ufn, "../");
150 else
152 if (strlen (ufn) + (q - p) + 1 >= ufnbuflen)
153 return 0;
154 string_cat_and_replace (ufn, p, q - p, '/', ':');
155 strcat (ufn, "/");
157 p = q + 1;
159 else
161 if (strlen (ufn) + (pe - p) >= ufnbuflen)
162 return 0;
163 string_cat_and_replace (ufn, p, pe - p, '/', ':');
164 /* no separator for last one */
165 p = pe;
169 return 1;
173 extern char *get_temp_dir_name ();
176 /* Convert a Posix pathname to Mac form. Approximately reverse of the
177 above in algorithm. */
180 posix_to_mac_pathname (const char *ufn, char *mfn, int mfnbuflen)
182 const char *p, *q, *pe;
183 char expanded_pathname[MAXPATHLEN+1];
185 strcpy (mfn, "");
187 if (*ufn == '\0')
188 return 1;
190 p = ufn;
192 /* Check for and handle volume names. Last comparison: strangely
193 somewhere "/.emacs" is passed. A temporary fix for now. */
194 if (*p == '/' && strchr (p+1, '/') == NULL && strcmp (p, "/.emacs") != 0)
196 if (strlen (p) + 1 > mfnbuflen)
197 return 0;
198 strcpy (mfn, p+1);
199 strcat (mfn, ":");
200 return 1;
203 /* expand to emacs dir found by init_emacs_passwd_dir */
204 if (strncmp (p, "~emacs/", 7) == 0)
206 struct passwd *pw = getpwnam ("emacs");
207 p += 7;
208 if (strlen (pw->pw_dir) + strlen (p) > MAXPATHLEN)
209 return 0;
210 strcpy (expanded_pathname, pw->pw_dir);
211 strcat (expanded_pathname, p);
212 p = expanded_pathname;
213 /* now p points to the pathname with emacs dir prefix */
215 else if (strncmp (p, "/tmp/", 5) == 0)
217 char *t = get_temp_dir_name ();
218 p += 5;
219 if (strlen (t) + strlen (p) > MAXPATHLEN)
220 return 0;
221 strcpy (expanded_pathname, t);
222 strcat (expanded_pathname, p);
223 p = expanded_pathname;
224 /* now p points to the pathname with emacs dir prefix */
226 else if (*p != '/') /* relative pathname */
227 strcat (mfn, ":");
229 if (*p == '/')
230 p++;
232 pe = p + strlen (p);
233 while (p < pe)
235 q = strchr (p, '/');
236 if (q)
238 if (q - p == 2 && *p == '.' && *(p+1) == '.')
240 if (strlen (mfn) + 1 >= mfnbuflen)
241 return 0;
242 strcat (mfn, ":");
244 else
246 if (strlen (mfn) + (q - p) + 1 >= mfnbuflen)
247 return 0;
248 string_cat_and_replace (mfn, p, q - p, ':', '/');
249 strcat (mfn, ":");
251 p = q + 1;
253 else
255 if (strlen (mfn) + (pe - p) >= mfnbuflen)
256 return 0;
257 string_cat_and_replace (mfn, p, pe - p, ':', '/');
258 p = pe;
262 return 1;
265 #if TARGET_API_MAC_CARBON
266 CFStringRef
267 cfstring_create_with_utf8_cstring (c_str)
268 const char *c_str;
270 CFStringRef str;
272 str = CFStringCreateWithCString (NULL, c_str, kCFStringEncodingUTF8);
273 if (str == NULL)
274 /* Failed to interpret as UTF 8. Fall back on Mac Roman. */
275 str = CFStringCreateWithCString (NULL, c_str, kCFStringEncodingMacRoman);
277 return str;
279 #endif
281 #ifndef MAC_OSX
283 /* The following functions with "sys_" prefix are stubs to Unix
284 functions that have already been implemented by CW or MPW. The
285 calls to them in Emacs source course are #define'd to call the sys_
286 versions by the header files s-mac.h. In these stubs pathnames are
287 converted between their Unix and Mac forms. */
290 /* Unix epoch is Jan 1, 1970 while Mac epoch is Jan 1, 1904: 66 years
291 + 17 leap days. These are for adjusting time values returned by
292 MacOS Toolbox functions. */
294 #define MAC_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
296 #ifdef __MWERKS__
297 #if __MSL__ < 0x6000
298 /* CW Pro 5 epoch is Jan 1, 1900 (aaarghhhhh!); remember, 1900 is not
299 a leap year! This is for adjusting time_t values returned by MSL
300 functions. */
301 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 70 + 17) * 24 * 60 * 60)
302 #else /* __MSL__ >= 0x6000 */
303 /* CW changes Pro 6 to follow Unix! */
304 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
305 #endif /* __MSL__ >= 0x6000 */
306 #elif __MRC__
307 /* MPW library functions follow Unix (confused?). */
308 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
309 #else /* not __MRC__ */
310 You lose!!!
311 #endif /* not __MRC__ */
314 /* Define our own stat function for both MrC and CW. The reason for
315 doing this: "stat" is both the name of a struct and function name:
316 can't use the same trick like that for sys_open, sys_close, etc. to
317 redirect Emacs's calls to our own version that converts Unix style
318 filenames to Mac style filename because all sorts of compilation
319 errors will be generated if stat is #define'd to be sys_stat. */
322 stat_noalias (const char *path, struct stat *buf)
324 char mac_pathname[MAXPATHLEN+1];
325 CInfoPBRec cipb;
327 if (posix_to_mac_pathname (path, mac_pathname, MAXPATHLEN+1) == 0)
328 return -1;
330 c2pstr (mac_pathname);
331 cipb.hFileInfo.ioNamePtr = mac_pathname;
332 cipb.hFileInfo.ioVRefNum = 0;
333 cipb.hFileInfo.ioDirID = 0;
334 cipb.hFileInfo.ioFDirIndex = 0;
335 /* set to 0 to get information about specific dir or file */
337 errno = PBGetCatInfo (&cipb, false);
338 if (errno == -43) /* -43: fnfErr defined in Errors.h */
339 errno = ENOENT;
340 if (errno != noErr)
341 return -1;
343 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* bit 4 = 1 for directories */
345 buf->st_mode = S_IFDIR | S_IREAD | S_IEXEC;
347 if (!(cipb.hFileInfo.ioFlAttrib & 0x1))
348 buf->st_mode |= S_IWRITE; /* bit 1 = 1 for locked files/directories */
349 buf->st_ino = cipb.dirInfo.ioDrDirID;
350 buf->st_dev = cipb.dirInfo.ioVRefNum;
351 buf->st_size = cipb.dirInfo.ioDrNmFls;
352 /* size of dir = number of files and dirs */
353 buf->st_atime
354 = buf->st_mtime
355 = cipb.dirInfo.ioDrMdDat - MAC_UNIX_EPOCH_DIFF;
356 buf->st_ctime = cipb.dirInfo.ioDrCrDat - MAC_UNIX_EPOCH_DIFF;
358 else
360 buf->st_mode = S_IFREG | S_IREAD;
361 if (!(cipb.hFileInfo.ioFlAttrib & 0x1))
362 buf->st_mode |= S_IWRITE; /* bit 1 = 1 for locked files/directories */
363 if (cipb.hFileInfo.ioFlFndrInfo.fdType == 'APPL')
364 buf->st_mode |= S_IEXEC;
365 buf->st_ino = cipb.hFileInfo.ioDirID;
366 buf->st_dev = cipb.hFileInfo.ioVRefNum;
367 buf->st_size = cipb.hFileInfo.ioFlLgLen;
368 buf->st_atime
369 = buf->st_mtime
370 = cipb.hFileInfo.ioFlMdDat - MAC_UNIX_EPOCH_DIFF;
371 buf->st_ctime = cipb.hFileInfo.ioFlCrDat - MAC_UNIX_EPOCH_DIFF;
374 if (cipb.hFileInfo.ioFlFndrInfo.fdFlags & 0x8000)
376 /* identify alias files as symlinks */
377 buf->st_mode &= ~S_IFREG;
378 buf->st_mode |= S_IFLNK;
381 buf->st_nlink = 1;
382 buf->st_uid = getuid ();
383 buf->st_gid = getgid ();
384 buf->st_rdev = 0;
386 return 0;
391 lstat (const char *path, struct stat *buf)
393 int result;
394 char true_pathname[MAXPATHLEN+1];
396 /* Try looking for the file without resolving aliases first. */
397 if ((result = stat_noalias (path, buf)) >= 0)
398 return result;
400 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
401 return -1;
403 return stat_noalias (true_pathname, buf);
408 stat (const char *path, struct stat *sb)
410 int result;
411 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
412 int len;
414 if ((result = stat_noalias (path, sb)) >= 0 &&
415 ! (sb->st_mode & S_IFLNK))
416 return result;
418 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
419 return -1;
421 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
422 if (len > -1)
424 fully_resolved_name[len] = '\0';
425 /* in fact our readlink terminates strings */
426 return lstat (fully_resolved_name, sb);
428 else
429 return lstat (true_pathname, sb);
433 #if __MRC__
434 /* CW defines fstat in stat.mac.c while MPW does not provide this
435 function. Without the information of how to get from a file
436 descriptor in MPW StdCLib to a Mac OS file spec, it should be hard
437 to implement this function. Fortunately, there is only one place
438 where this function is called in our configuration: in fileio.c,
439 where only the st_dev and st_ino fields are used to determine
440 whether two fildes point to different i-nodes to prevent copying
441 a file onto itself equal. What we have here probably needs
442 improvement. */
445 fstat (int fildes, struct stat *buf)
447 buf->st_dev = 0;
448 buf->st_ino = fildes;
449 buf->st_mode = S_IFREG; /* added by T.I. for the copy-file */
450 return 0; /* success */
452 #endif /* __MRC__ */
456 mkdir (const char *dirname, int mode)
458 #pragma unused(mode)
460 HFileParam hfpb;
461 char true_pathname[MAXPATHLEN+1], mac_pathname[MAXPATHLEN+1];
463 if (find_true_pathname (dirname, true_pathname, MAXPATHLEN+1) == -1)
464 return -1;
466 if (posix_to_mac_pathname (true_pathname, mac_pathname, MAXPATHLEN+1) == 0)
467 return -1;
469 c2pstr (mac_pathname);
470 hfpb.ioNamePtr = mac_pathname;
471 hfpb.ioVRefNum = 0; /* ignored unless name is invalid */
472 hfpb.ioDirID = 0; /* parent is the root */
474 errno = PBDirCreate ((HParmBlkPtr) &hfpb, false);
475 /* just return the Mac OSErr code for now */
476 return errno == noErr ? 0 : -1;
480 #undef rmdir
481 sys_rmdir (const char *dirname)
483 HFileParam hfpb;
484 char mac_pathname[MAXPATHLEN+1];
486 if (posix_to_mac_pathname (dirname, mac_pathname, MAXPATHLEN+1) == 0)
487 return -1;
489 c2pstr (mac_pathname);
490 hfpb.ioNamePtr = mac_pathname;
491 hfpb.ioVRefNum = 0; /* ignored unless name is invalid */
492 hfpb.ioDirID = 0; /* parent is the root */
494 errno = PBHDelete ((HParmBlkPtr) &hfpb, false);
495 return errno == noErr ? 0 : -1;
499 #ifdef __MRC__
500 /* No implementation yet. */
502 execvp (const char *path, ...)
504 return -1;
506 #endif /* __MRC__ */
510 utime (const char *path, const struct utimbuf *times)
512 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
513 int len;
514 char mac_pathname[MAXPATHLEN+1];
515 CInfoPBRec cipb;
517 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
518 return -1;
520 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
521 if (len > -1)
522 fully_resolved_name[len] = '\0';
523 else
524 strcpy (fully_resolved_name, true_pathname);
526 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
527 return -1;
529 c2pstr (mac_pathname);
530 cipb.hFileInfo.ioNamePtr = mac_pathname;
531 cipb.hFileInfo.ioVRefNum = 0;
532 cipb.hFileInfo.ioDirID = 0;
533 cipb.hFileInfo.ioFDirIndex = 0;
534 /* set to 0 to get information about specific dir or file */
536 errno = PBGetCatInfo (&cipb, false);
537 if (errno != noErr)
538 return -1;
540 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* bit 4 = 1 for directories */
542 if (times)
543 cipb.dirInfo.ioDrMdDat = times->modtime + MAC_UNIX_EPOCH_DIFF;
544 else
545 GetDateTime (&cipb.dirInfo.ioDrMdDat);
547 else
549 if (times)
550 cipb.hFileInfo.ioFlMdDat = times->modtime + MAC_UNIX_EPOCH_DIFF;
551 else
552 GetDateTime (&cipb.hFileInfo.ioFlMdDat);
555 errno = PBSetCatInfo (&cipb, false);
556 return errno == noErr ? 0 : -1;
560 #ifndef F_OK
561 #define F_OK 0
562 #endif
563 #ifndef X_OK
564 #define X_OK 1
565 #endif
566 #ifndef W_OK
567 #define W_OK 2
568 #endif
570 /* Like stat, but test for access mode in hfpb.ioFlAttrib */
572 access (const char *path, int mode)
574 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
575 int len;
576 char mac_pathname[MAXPATHLEN+1];
577 CInfoPBRec cipb;
579 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
580 return -1;
582 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
583 if (len > -1)
584 fully_resolved_name[len] = '\0';
585 else
586 strcpy (fully_resolved_name, true_pathname);
588 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
589 return -1;
591 c2pstr (mac_pathname);
592 cipb.hFileInfo.ioNamePtr = mac_pathname;
593 cipb.hFileInfo.ioVRefNum = 0;
594 cipb.hFileInfo.ioDirID = 0;
595 cipb.hFileInfo.ioFDirIndex = 0;
596 /* set to 0 to get information about specific dir or file */
598 errno = PBGetCatInfo (&cipb, false);
599 if (errno != noErr)
600 return -1;
602 if (mode == F_OK) /* got this far, file exists */
603 return 0;
605 if (mode & X_OK)
606 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* path refers to a directory */
607 return 0;
608 else
610 if (cipb.hFileInfo.ioFlFndrInfo.fdType == 'APPL')
611 return 0;
612 else
613 return -1;
616 if (mode & W_OK)
617 return (cipb.hFileInfo.ioFlAttrib & 0x1) ? -1 : 0;
618 /* don't allow if lock bit is on */
620 return -1;
624 #define DEV_NULL_FD 0x10000
626 #undef open
628 sys_open (const char *path, int oflag)
630 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
631 int len;
632 char mac_pathname[MAXPATHLEN+1];
634 if (strcmp (path, "/dev/null") == 0)
635 return DEV_NULL_FD; /* some bogus fd to be ignored in write */
637 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
638 return -1;
640 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
641 if (len > -1)
642 fully_resolved_name[len] = '\0';
643 else
644 strcpy (fully_resolved_name, true_pathname);
646 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
647 return -1;
648 else
650 #ifdef __MRC__
651 int res = open (mac_pathname, oflag);
652 /* if (oflag == O_WRONLY || oflag == O_RDWR) */
653 if (oflag & O_CREAT)
654 fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
655 return res;
656 #else /* not __MRC__ */
657 return open (mac_pathname, oflag);
658 #endif /* not __MRC__ */
663 #undef creat
665 sys_creat (const char *path, mode_t mode)
667 char true_pathname[MAXPATHLEN+1];
668 int len;
669 char mac_pathname[MAXPATHLEN+1];
671 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
672 return -1;
674 if (!posix_to_mac_pathname (true_pathname, mac_pathname, MAXPATHLEN+1))
675 return -1;
676 else
678 #ifdef __MRC__
679 int result = creat (mac_pathname);
680 fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
681 return result;
682 #else /* not __MRC__ */
683 return creat (mac_pathname, mode);
684 #endif /* not __MRC__ */
689 #undef unlink
691 sys_unlink (const char *path)
693 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
694 int len;
695 char mac_pathname[MAXPATHLEN+1];
697 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
698 return -1;
700 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
701 if (len > -1)
702 fully_resolved_name[len] = '\0';
703 else
704 strcpy (fully_resolved_name, true_pathname);
706 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
707 return -1;
708 else
709 return unlink (mac_pathname);
713 #undef read
715 sys_read (int fildes, char *buf, int count)
717 if (fildes == 0) /* this should not be used for console input */
718 return -1;
719 else
720 #if __MSL__ >= 0x6000
721 return _read (fildes, buf, count);
722 #else
723 return read (fildes, buf, count);
724 #endif
728 #undef write
730 sys_write (int fildes, const char *buf, int count)
732 if (fildes == DEV_NULL_FD)
733 return count;
734 else
735 #if __MSL__ >= 0x6000
736 return _write (fildes, buf, count);
737 #else
738 return write (fildes, buf, count);
739 #endif
743 #undef rename
745 sys_rename (const char * old_name, const char * new_name)
747 char true_old_pathname[MAXPATHLEN+1], true_new_pathname[MAXPATHLEN+1];
748 char fully_resolved_old_name[MAXPATHLEN+1];
749 int len;
750 char mac_old_name[MAXPATHLEN+1], mac_new_name[MAXPATHLEN+1];
752 if (find_true_pathname (old_name, true_old_pathname, MAXPATHLEN+1) == -1)
753 return -1;
755 len = readlink (true_old_pathname, fully_resolved_old_name, MAXPATHLEN);
756 if (len > -1)
757 fully_resolved_old_name[len] = '\0';
758 else
759 strcpy (fully_resolved_old_name, true_old_pathname);
761 if (find_true_pathname (new_name, true_new_pathname, MAXPATHLEN+1) == -1)
762 return -1;
764 if (strcmp (fully_resolved_old_name, true_new_pathname) == 0)
765 return 0;
767 if (!posix_to_mac_pathname (fully_resolved_old_name,
768 mac_old_name,
769 MAXPATHLEN+1))
770 return -1;
772 if (!posix_to_mac_pathname(true_new_pathname, mac_new_name, MAXPATHLEN+1))
773 return -1;
775 /* If a file with new_name already exists, rename deletes the old
776 file in Unix. CW version fails in these situation. So we add a
777 call to unlink here. */
778 (void) unlink (mac_new_name);
780 return rename (mac_old_name, mac_new_name);
784 #undef fopen
785 extern FILE *fopen (const char *name, const char *mode);
786 FILE *
787 sys_fopen (const char *name, const char *mode)
789 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
790 int len;
791 char mac_pathname[MAXPATHLEN+1];
793 if (find_true_pathname (name, true_pathname, MAXPATHLEN+1) == -1)
794 return 0;
796 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
797 if (len > -1)
798 fully_resolved_name[len] = '\0';
799 else
800 strcpy (fully_resolved_name, true_pathname);
802 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
803 return 0;
804 else
806 #ifdef __MRC__
807 if (mode[0] == 'w' || mode[0] == 'a')
808 fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
809 #endif /* not __MRC__ */
810 return fopen (mac_pathname, mode);
815 #include <Events.h>
817 long target_ticks = 0;
819 #ifdef __MRC__
820 __sigfun alarm_signal_func = (__sigfun) 0;
821 #elif __MWERKS__
822 __signal_func_ptr alarm_signal_func = (__signal_func_ptr) 0;
823 #else /* not __MRC__ and not __MWERKS__ */
824 You lose!!!
825 #endif /* not __MRC__ and not __MWERKS__ */
828 /* These functions simulate SIG_ALRM. The stub for function signal
829 stores the signal handler function in alarm_signal_func if a
830 SIG_ALRM is encountered. check_alarm is called in XTread_socket,
831 which emacs calls periodically. A pending alarm is represented by
832 a non-zero target_ticks value. check_alarm calls the handler
833 function pointed to by alarm_signal_func if one has been set up and
834 an alarm is pending. */
836 void
837 check_alarm ()
839 if (target_ticks && TickCount () > target_ticks)
841 target_ticks = 0;
842 if (alarm_signal_func)
843 (*alarm_signal_func)(SIGALRM);
849 select (n, rfds, wfds, efds, timeout)
850 int n;
851 SELECT_TYPE *rfds;
852 SELECT_TYPE *wfds;
853 SELECT_TYPE *efds;
854 struct timeval *timeout;
856 #ifdef TARGET_API_MAC_CARBON
857 return 1;
858 #else /* not TARGET_API_MAC_CARBON */
859 EMACS_TIME end_time, now;
860 EventRecord e;
862 /* Can only handle wait for keyboard input. */
863 if (n > 1 || wfds || efds)
864 return -1;
866 EMACS_GET_TIME (end_time);
867 EMACS_ADD_TIME (end_time, end_time, *timeout);
871 /* Also return true if an event other than a keyDown has
872 occurred. This causes kbd_buffer_get_event in keyboard.c to
873 call read_avail_input which in turn calls XTread_socket to
874 poll for these events. Otherwise these never get processed
875 except but a very slow poll timer. */
876 if (FD_ISSET (0, rfds) && EventAvail (everyEvent, &e))
877 return 1;
879 /* Also check movement of the mouse. */
881 Point mouse_pos;
882 static Point old_mouse_pos = {-1, -1};
884 GetMouse (&mouse_pos);
885 if (!EqualPt (mouse_pos, old_mouse_pos))
887 old_mouse_pos = mouse_pos;
888 return 1;
892 WaitNextEvent (0, &e, 1UL, NULL); /* Accept no event; wait 1
893 tic. by T.I. */
895 EMACS_GET_TIME (now);
896 EMACS_SUB_TIME (now, end_time, now);
898 while (!EMACS_TIME_NEG_P (now));
900 return 0;
901 #endif /* not TARGET_API_MAC_CARBON */
905 /* Called in sys_select to wait for an alarm signal to arrive. */
908 pause ()
910 EventRecord e;
911 unsigned long tick;
913 if (!target_ticks) /* no alarm pending */
914 return -1;
916 if ((tick = TickCount ()) < target_ticks)
917 WaitNextEvent (0, &e, target_ticks - tick, NULL); /* Accept no event;
918 just wait. by T.I. */
920 target_ticks = 0;
921 if (alarm_signal_func)
922 (*alarm_signal_func)(SIGALRM);
924 return 0;
929 alarm (int seconds)
931 long remaining = target_ticks ? (TickCount () - target_ticks) / 60 : 0;
933 target_ticks = seconds ? TickCount () + 60 * seconds : 0;
935 return (remaining < 0) ? 0 : (unsigned int) remaining;
939 #undef signal
940 #ifdef __MRC__
941 extern __sigfun signal (int signal, __sigfun signal_func);
942 __sigfun
943 sys_signal (int signal_num, __sigfun signal_func)
944 #elif __MWERKS__
945 extern __signal_func_ptr signal (int signal, __signal_func_ptr signal_func);
946 __signal_func_ptr
947 sys_signal (int signal_num, __signal_func_ptr signal_func)
948 #else /* not __MRC__ and not __MWERKS__ */
949 You lose!!!
950 #endif /* not __MRC__ and not __MWERKS__ */
952 if (signal_num != SIGALRM)
953 return signal (signal_num, signal_func);
954 else
956 #ifdef __MRC__
957 __sigfun old_signal_func;
958 #elif __MWERKS__
959 __signal_func_ptr old_signal_func;
960 #else
961 You lose!!!
962 #endif
963 old_signal_func = alarm_signal_func;
964 alarm_signal_func = signal_func;
965 return old_signal_func;
970 /* gettimeofday should return the amount of time (in a timeval
971 structure) since midnight today. The toolbox function Microseconds
972 returns the number of microseconds (in a UnsignedWide value) since
973 the machine was booted. Also making this complicated is WideAdd,
974 WideSubtract, etc. take wide values. */
977 gettimeofday (tp)
978 struct timeval *tp;
980 static inited = 0;
981 static wide wall_clock_at_epoch, clicks_at_epoch;
982 UnsignedWide uw_microseconds;
983 wide w_microseconds;
984 time_t sys_time (time_t *);
986 /* If this function is called for the first time, record the number
987 of seconds since midnight and the number of microseconds since
988 boot at the time of this first call. */
989 if (!inited)
991 time_t systime;
992 inited = 1;
993 systime = sys_time (NULL);
994 /* Store microseconds since midnight in wall_clock_at_epoch. */
995 WideMultiply (systime, 1000000L, &wall_clock_at_epoch);
996 Microseconds (&uw_microseconds);
997 /* Store microseconds since boot in clicks_at_epoch. */
998 clicks_at_epoch.hi = uw_microseconds.hi;
999 clicks_at_epoch.lo = uw_microseconds.lo;
1002 /* Get time since boot */
1003 Microseconds (&uw_microseconds);
1005 /* Convert to time since midnight*/
1006 w_microseconds.hi = uw_microseconds.hi;
1007 w_microseconds.lo = uw_microseconds.lo;
1008 WideSubtract (&w_microseconds, &clicks_at_epoch);
1009 WideAdd (&w_microseconds, &wall_clock_at_epoch);
1010 tp->tv_sec = WideDivide (&w_microseconds, 1000000L, &tp->tv_usec);
1012 return 0;
1016 #ifdef __MRC__
1017 unsigned int
1018 sleep (unsigned int seconds)
1020 unsigned long time_up;
1021 EventRecord e;
1023 time_up = TickCount () + seconds * 60;
1024 while (TickCount () < time_up)
1026 /* Accept no event; just wait. by T.I. */
1027 WaitNextEvent (0, &e, 30, NULL);
1030 return (0);
1032 #endif /* __MRC__ */
1035 /* The time functions adjust time values according to the difference
1036 between the Unix and CW epoches. */
1038 #undef gmtime
1039 extern struct tm *gmtime (const time_t *);
1040 struct tm *
1041 sys_gmtime (const time_t *timer)
1043 time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
1045 return gmtime (&unix_time);
1049 #undef localtime
1050 extern struct tm *localtime (const time_t *);
1051 struct tm *
1052 sys_localtime (const time_t *timer)
1054 #if __MSL__ >= 0x6000
1055 time_t unix_time = *timer;
1056 #else
1057 time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
1058 #endif
1060 return localtime (&unix_time);
1064 #undef ctime
1065 extern char *ctime (const time_t *);
1066 char *
1067 sys_ctime (const time_t *timer)
1069 #if __MSL__ >= 0x6000
1070 time_t unix_time = *timer;
1071 #else
1072 time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
1073 #endif
1075 return ctime (&unix_time);
1079 #undef time
1080 extern time_t time (time_t *);
1081 time_t
1082 sys_time (time_t *timer)
1084 #if __MSL__ >= 0x6000
1085 time_t mac_time = time (NULL);
1086 #else
1087 time_t mac_time = time (NULL) - CW_OR_MPW_UNIX_EPOCH_DIFF;
1088 #endif
1090 if (timer)
1091 *timer = mac_time;
1093 return mac_time;
1097 /* MPW strftime broken for "%p" format */
1098 #ifdef __MRC__
1099 #undef strftime
1100 #include <time.h>
1101 size_t
1102 sys_strftime (char * s, size_t maxsize, const char * format,
1103 const struct tm * timeptr)
1105 if (strcmp (format, "%p") == 0)
1107 if (maxsize < 3)
1108 return 0;
1109 if (timeptr->tm_hour < 12)
1111 strcpy (s, "AM");
1112 return 2;
1114 else
1116 strcpy (s, "PM");
1117 return 2;
1120 else
1121 return strftime (s, maxsize, format, timeptr);
1123 #endif /* __MRC__ */
1126 /* no subprocesses, empty wait */
1129 wait (int pid)
1131 return 0;
1135 void
1136 croak (char *badfunc)
1138 printf ("%s not yet implemented\r\n", badfunc);
1139 exit (1);
1143 char *
1144 index (const char * str, int chr)
1146 return strchr (str, chr);
1150 char *
1151 mktemp (char *template)
1153 int len, k;
1154 static seqnum = 0;
1156 len = strlen (template);
1157 k = len - 1;
1158 while (k >= 0 && template[k] == 'X')
1159 k--;
1161 k++; /* make k index of first 'X' */
1163 if (k < len)
1165 /* Zero filled, number of digits equal to the number of X's. */
1166 sprintf (&template[k], "%0*d", len-k, seqnum++);
1168 return template;
1170 else
1171 return 0;
1175 /* Emulate getpwuid, getpwnam and others. */
1177 #define PASSWD_FIELD_SIZE 256
1179 static char my_passwd_name[PASSWD_FIELD_SIZE];
1180 static char my_passwd_dir[MAXPATHLEN+1];
1182 static struct passwd my_passwd =
1184 my_passwd_name,
1185 my_passwd_dir,
1188 static struct group my_group =
1190 /* There are no groups on the mac, so we just return "root" as the
1191 group name. */
1192 "root",
1196 /* Initialized by main () in macterm.c to pathname of emacs directory. */
1198 char emacs_passwd_dir[MAXPATHLEN+1];
1200 char *
1201 getwd (char *);
1203 void
1204 init_emacs_passwd_dir ()
1206 int found = false;
1208 if (getwd (emacs_passwd_dir) && getwd (my_passwd_dir))
1210 /* Need pathname of first ancestor that begins with "emacs"
1211 since Mac emacs application is somewhere in the emacs-*
1212 tree. */
1213 int len = strlen (emacs_passwd_dir);
1214 int j = len - 1;
1215 /* j points to the "/" following the directory name being
1216 compared. */
1217 int i = j - 1;
1218 while (i >= 0 && !found)
1220 while (i >= 0 && emacs_passwd_dir[i] != '/')
1221 i--;
1222 if (emacs_passwd_dir[i] == '/' && i+5 < len)
1223 found = (strncmp (&(emacs_passwd_dir[i+1]), "emacs", 5) == 0);
1224 if (found)
1225 emacs_passwd_dir[j+1] = '\0';
1226 else
1228 j = i;
1229 i = j - 1;
1234 if (!found)
1236 /* Setting to "/" probably won't work but set it to something
1237 anyway. */
1238 strcpy (emacs_passwd_dir, "/");
1239 strcpy (my_passwd_dir, "/");
1244 static struct passwd emacs_passwd =
1246 "emacs",
1247 emacs_passwd_dir,
1250 static int my_passwd_inited = 0;
1253 static void
1254 init_my_passwd ()
1256 char **owner_name;
1258 /* Note: my_passwd_dir initialized in int_emacs_passwd_dir to
1259 directory where Emacs was started. */
1261 owner_name = (char **) GetResource ('STR ',-16096);
1262 if (owner_name)
1264 HLock (owner_name);
1265 BlockMove ((unsigned char *) *owner_name,
1266 (unsigned char *) my_passwd_name,
1267 *owner_name[0]+1);
1268 HUnlock (owner_name);
1269 p2cstr ((unsigned char *) my_passwd_name);
1271 else
1272 my_passwd_name[0] = 0;
1276 struct passwd *
1277 getpwuid (uid_t uid)
1279 if (!my_passwd_inited)
1281 init_my_passwd ();
1282 my_passwd_inited = 1;
1285 return &my_passwd;
1289 struct group *
1290 getgrgid (gid_t gid)
1292 return &my_group;
1296 struct passwd *
1297 getpwnam (const char *name)
1299 if (strcmp (name, "emacs") == 0)
1300 return &emacs_passwd;
1302 if (!my_passwd_inited)
1304 init_my_passwd ();
1305 my_passwd_inited = 1;
1308 return &my_passwd;
1312 /* The functions fork, kill, sigsetmask, sigblock, request_sigio,
1313 setpgrp, setpriority, and unrequest_sigio are defined to be empty
1314 as in msdos.c. */
1318 fork ()
1320 return -1;
1325 kill (int x, int y)
1327 return -1;
1331 void
1332 sys_subshell ()
1334 error ("Can't spawn subshell");
1339 sigsetmask (int x)
1341 return 0;
1346 sigblock (int mask)
1348 return 0;
1352 void
1353 request_sigio (void)
1358 void
1359 unrequest_sigio (void)
1365 setpgrp ()
1367 return 0;
1371 /* No pipes yet. */
1374 pipe (int _fildes[2])
1376 errno = EACCES;
1377 return -1;
1381 /* Hard and symbolic links. */
1384 symlink (const char *name1, const char *name2)
1386 errno = ENOENT;
1387 return -1;
1392 link (const char *name1, const char *name2)
1394 errno = ENOENT;
1395 return -1;
1398 #endif /* ! MAC_OSX */
1400 /* Determine the path name of the file specified by VREFNUM, DIRID,
1401 and NAME and place that in the buffer PATH of length
1402 MAXPATHLEN. */
1404 path_from_vol_dir_name (char *path, int man_path_len, short vol_ref_num,
1405 long dir_id, ConstStr255Param name)
1407 Str255 dir_name;
1408 CInfoPBRec cipb;
1409 OSErr err;
1411 if (strlen (name) > man_path_len)
1412 return 0;
1414 memcpy (dir_name, name, name[0]+1);
1415 memcpy (path, name, name[0]+1);
1416 p2cstr (path);
1418 cipb.dirInfo.ioDrParID = dir_id;
1419 cipb.dirInfo.ioNamePtr = dir_name;
1423 cipb.dirInfo.ioVRefNum = vol_ref_num;
1424 cipb.dirInfo.ioFDirIndex = -1;
1425 cipb.dirInfo.ioDrDirID = cipb.dirInfo.ioDrParID;
1426 /* go up to parent each time */
1428 err = PBGetCatInfo (&cipb, false);
1429 if (err != noErr)
1430 return 0;
1432 p2cstr (dir_name);
1433 if (strlen (dir_name) + strlen (path) + 1 >= man_path_len)
1434 return 0;
1436 strcat (dir_name, ":");
1437 strcat (dir_name, path);
1438 /* attach to front since we're going up directory tree */
1439 strcpy (path, dir_name);
1441 while (cipb.dirInfo.ioDrDirID != fsRtDirID);
1442 /* stop when we see the volume's root directory */
1444 return 1; /* success */
1447 #ifndef MAC_OSX
1450 readlink (const char *path, char *buf, int bufsiz)
1452 char mac_sym_link_name[MAXPATHLEN+1];
1453 OSErr err;
1454 FSSpec fsspec;
1455 Boolean target_is_folder, was_aliased;
1456 Str255 directory_name, mac_pathname;
1457 CInfoPBRec cipb;
1459 if (posix_to_mac_pathname (path, mac_sym_link_name, MAXPATHLEN+1) == 0)
1460 return -1;
1462 c2pstr (mac_sym_link_name);
1463 err = FSMakeFSSpec (0, 0, mac_sym_link_name, &fsspec);
1464 if (err != noErr)
1466 errno = ENOENT;
1467 return -1;
1470 err = ResolveAliasFile (&fsspec, true, &target_is_folder, &was_aliased);
1471 if (err != noErr || !was_aliased)
1473 errno = ENOENT;
1474 return -1;
1477 if (path_from_vol_dir_name (mac_pathname, 255, fsspec.vRefNum, fsspec.parID,
1478 fsspec.name) == 0)
1480 errno = ENOENT;
1481 return -1;
1484 if (mac_to_posix_pathname (mac_pathname, buf, bufsiz) == 0)
1486 errno = ENOENT;
1487 return -1;
1490 return strlen (buf);
1494 /* Convert a path to one with aliases fully expanded. */
1496 static int
1497 find_true_pathname (const char *path, char *buf, int bufsiz)
1499 char *q, temp[MAXPATHLEN+1];
1500 const char *p;
1501 int len;
1503 if (bufsiz <= 0 || path == 0 || path[0] == '\0')
1504 return -1;
1506 buf[0] = '\0';
1508 p = path;
1509 if (*p == '/')
1510 q = strchr (p + 1, '/');
1511 else
1512 q = strchr (p, '/');
1513 len = 0; /* loop may not be entered, e.g., for "/" */
1515 while (q)
1517 strcpy (temp, buf);
1518 strncat (temp, p, q - p);
1519 len = readlink (temp, buf, bufsiz);
1520 if (len <= -1)
1522 if (strlen (temp) + 1 > bufsiz)
1523 return -1;
1524 strcpy (buf, temp);
1526 strcat (buf, "/");
1527 len++;
1528 p = q + 1;
1529 q = strchr(p, '/');
1532 if (len + strlen (p) + 1 >= bufsiz)
1533 return -1;
1535 strcat (buf, p);
1536 return len + strlen (p);
1540 mode_t
1541 umask (mode_t numask)
1543 static mode_t mask = 022;
1544 mode_t oldmask = mask;
1545 mask = numask;
1546 return oldmask;
1551 chmod (const char *path, mode_t mode)
1553 /* say it always succeed for now */
1554 return 0;
1559 dup (int oldd)
1561 #ifdef __MRC__
1562 return fcntl (oldd, F_DUPFD, 0);
1563 #elif __MWERKS__
1564 /* current implementation of fcntl in fcntl.mac.c simply returns old
1565 descriptor */
1566 return fcntl (oldd, F_DUPFD);
1567 #else
1568 You lose!!!
1569 #endif
1573 /* This is from the original sysdep.c. Emulate BSD dup2. First close
1574 newd if it already exists. Then, attempt to dup oldd. If not
1575 successful, call dup2 recursively until we are, then close the
1576 unsuccessful ones. */
1579 dup2 (int oldd, int newd)
1581 int fd, ret;
1583 close (newd);
1585 fd = dup (oldd);
1586 if (fd == -1)
1587 return -1;
1588 if (fd == newd)
1589 return newd;
1590 ret = dup2 (oldd, newd);
1591 close (fd);
1592 return ret;
1596 /* let it fail for now */
1598 char *
1599 sbrk (int incr)
1601 return (char *) -1;
1606 fsync (int fd)
1608 return 0;
1613 ioctl (int d, int request, void *argp)
1615 return -1;
1619 #ifdef __MRC__
1621 isatty (int fildes)
1623 if (fildes >=0 && fildes <= 2)
1624 return 1;
1625 else
1626 return 0;
1631 getgid ()
1633 return 100;
1638 getegid ()
1640 return 100;
1645 getuid ()
1647 return 200;
1652 geteuid ()
1654 return 200;
1656 #endif /* __MRC__ */
1659 #ifdef __MWERKS__
1660 #if __MSL__ < 0x6000
1661 #undef getpid
1663 getpid ()
1665 return 9999;
1667 #endif
1668 #endif /* __MWERKS__ */
1670 #endif /* ! MAC_OSX */
1673 /* Return the path to the directory in which Emacs can create
1674 temporary files. The MacOS "temporary items" directory cannot be
1675 used because it removes the file written by a process when it
1676 exits. In that sense it's more like "/dev/null" than "/tmp" (but
1677 again not exactly). And of course Emacs needs to read back the
1678 files written by its subprocesses. So here we write the files to a
1679 directory "Emacs" in the Preferences Folder. This directory is
1680 created if it does not exist. */
1682 char *
1683 get_temp_dir_name ()
1685 static char *temp_dir_name = NULL;
1686 short vol_ref_num;
1687 long dir_id;
1688 OSErr err;
1689 Str255 dir_name, full_path;
1690 CInfoPBRec cpb;
1691 char unix_dir_name[MAXPATHLEN+1];
1692 DIR *dir;
1694 /* Cache directory name with pointer temp_dir_name.
1695 Look for it only the first time. */
1696 if (!temp_dir_name)
1698 err = FindFolder (kOnSystemDisk, kPreferencesFolderType, kCreateFolder,
1699 &vol_ref_num, &dir_id);
1700 if (err != noErr)
1701 return NULL;
1703 if (!path_from_vol_dir_name (full_path, 255, vol_ref_num, dir_id, "\p"))
1704 return NULL;
1706 if (strlen (full_path) + 6 <= MAXPATHLEN)
1707 strcat (full_path, "Emacs:");
1708 else
1709 return NULL;
1711 if (!mac_to_posix_pathname (full_path, unix_dir_name, MAXPATHLEN+1))
1712 return NULL;
1714 dir = opendir (unix_dir_name); /* check whether temp directory exists */
1715 if (dir)
1716 closedir (dir);
1717 else if (mkdir (unix_dir_name, 0700) != 0) /* create it if not */
1718 return NULL;
1720 temp_dir_name = (char *) malloc (strlen (unix_dir_name) + 1);
1721 strcpy (temp_dir_name, unix_dir_name);
1724 return temp_dir_name;
1727 #ifndef MAC_OSX
1729 /* Allocate and construct an array of pointers to strings from a list
1730 of strings stored in a 'STR#' resource. The returned pointer array
1731 is stored in the style of argv and environ: if the 'STR#' resource
1732 contains numString strings, a pointer array with numString+1
1733 elements is returned in which the last entry contains a null
1734 pointer. The pointer to the pointer array is passed by pointer in
1735 parameter t. The resource ID of the 'STR#' resource is passed in
1736 parameter StringListID.
1739 void
1740 get_string_list (char ***t, short string_list_id)
1742 Handle h;
1743 Ptr p;
1744 int i, num_strings;
1746 h = GetResource ('STR#', string_list_id);
1747 if (h)
1749 HLock (h);
1750 p = *h;
1751 num_strings = * (short *) p;
1752 p += sizeof(short);
1753 *t = (char **) malloc (sizeof (char *) * (num_strings + 1));
1754 for (i = 0; i < num_strings; i++)
1756 short length = *p++;
1757 (*t)[i] = (char *) malloc (length + 1);
1758 strncpy ((*t)[i], p, length);
1759 (*t)[i][length] = '\0';
1760 p += length;
1762 (*t)[num_strings] = 0;
1763 HUnlock (h);
1765 else
1767 /* Return no string in case GetResource fails. Bug fixed by
1768 Ikegami Tsutomu. Caused MPW build to crash without sym -on
1769 option (no sym -on implies -opt local). */
1770 *t = (char **) malloc (sizeof (char *));
1771 (*t)[0] = 0;
1776 static char *
1777 get_path_to_system_folder ()
1779 short vol_ref_num;
1780 long dir_id;
1781 OSErr err;
1782 Str255 dir_name, full_path;
1783 CInfoPBRec cpb;
1784 static char system_folder_unix_name[MAXPATHLEN+1];
1785 DIR *dir;
1787 err = FindFolder (kOnSystemDisk, kSystemFolderType, kDontCreateFolder,
1788 &vol_ref_num, &dir_id);
1789 if (err != noErr)
1790 return NULL;
1792 if (!path_from_vol_dir_name (full_path, 255, vol_ref_num, dir_id, "\p"))
1793 return NULL;
1795 if (!mac_to_posix_pathname (full_path, system_folder_unix_name,
1796 MAXPATHLEN+1))
1797 return NULL;
1799 return system_folder_unix_name;
1803 char **environ;
1805 #define ENVIRON_STRING_LIST_ID 128
1807 /* Get environment variable definitions from STR# resource. */
1809 void
1810 init_environ ()
1812 int i;
1814 get_string_list (&environ, ENVIRON_STRING_LIST_ID);
1816 i = 0;
1817 while (environ[i])
1818 i++;
1820 /* Make HOME directory the one Emacs starts up in if not specified
1821 by resource. */
1822 if (getenv ("HOME") == NULL)
1824 environ = (char **) realloc (environ, sizeof (char *) * (i + 2));
1825 if (environ)
1827 environ[i] = (char *) malloc (strlen (my_passwd_dir) + 6);
1828 if (environ[i])
1830 strcpy (environ[i], "HOME=");
1831 strcat (environ[i], my_passwd_dir);
1833 environ[i+1] = 0;
1834 i++;
1838 /* Make HOME directory the one Emacs starts up in if not specified
1839 by resource. */
1840 if (getenv ("MAIL") == NULL)
1842 environ = (char **) realloc (environ, sizeof (char *) * (i + 2));
1843 if (environ)
1845 char * path_to_system_folder = get_path_to_system_folder ();
1846 environ[i] = (char *) malloc (strlen (path_to_system_folder) + 22);
1847 if (environ[i])
1849 strcpy (environ[i], "MAIL=");
1850 strcat (environ[i], path_to_system_folder);
1851 strcat (environ[i], "Eudora Folder/In");
1853 environ[i+1] = 0;
1859 /* Return the value of the environment variable NAME. */
1861 char *
1862 getenv (const char *name)
1864 int length = strlen(name);
1865 char **e;
1867 for (e = environ; *e != 0; e++)
1868 if (strncmp(*e, name, length) == 0 && (*e)[length] == '=')
1869 return &(*e)[length + 1];
1871 if (strcmp (name, "TMPDIR") == 0)
1872 return get_temp_dir_name ();
1874 return 0;
1878 #ifdef __MRC__
1879 /* see Interfaces&Libraries:Interfaces:CIncludes:signal.h */
1880 char *sys_siglist[] =
1882 "Zero is not a signal!!!",
1883 "Abort", /* 1 */
1884 "Interactive user interrupt", /* 2 */ "?",
1885 "Floating point exception", /* 4 */ "?", "?", "?",
1886 "Illegal instruction", /* 8 */ "?", "?", "?", "?", "?", "?", "?",
1887 "Segment violation", /* 16 */ "?", "?", "?", "?", "?", "?", "?",
1888 "?", "?", "?", "?", "?", "?", "?", "?",
1889 "Terminal" /* 32 */
1891 #elif __MWERKS__
1892 char *sys_siglist[] =
1894 "Zero is not a signal!!!",
1895 "Abort",
1896 "Floating point exception",
1897 "Illegal instruction",
1898 "Interactive user interrupt",
1899 "Segment violation",
1900 "Terminal"
1902 #else /* not __MRC__ and not __MWERKS__ */
1903 You lose!!!
1904 #endif /* not __MRC__ and not __MWERKS__ */
1907 #include <utsname.h>
1910 uname (struct utsname *name)
1912 char **system_name;
1913 system_name = GetString (-16413); /* IM - Resource Manager Reference */
1914 if (system_name)
1916 BlockMove (*system_name, name->nodename, (*system_name)[0]+1);
1917 p2cstr (name->nodename);
1918 return 0;
1920 else
1921 return -1;
1925 #include <Processes.h>
1926 #include <EPPC.h>
1928 /* Event class of HLE sent to subprocess. */
1929 const OSType kEmacsSubprocessSend = 'ESND';
1931 /* Event class of HLE sent back from subprocess. */
1932 const OSType kEmacsSubprocessReply = 'ERPY';
1935 char *
1936 mystrchr (char *s, char c)
1938 while (*s && *s != c)
1940 if (*s == '\\')
1941 s++;
1942 s++;
1945 if (*s)
1947 *s = '\0';
1948 return s;
1950 else
1951 return NULL;
1955 char *
1956 mystrtok (char *s)
1958 while (*s)
1959 s++;
1961 return s + 1;
1965 void
1966 mystrcpy (char *to, char *from)
1968 while (*from)
1970 if (*from == '\\')
1971 from++;
1972 *to++ = *from++;
1974 *to = '\0';
1978 /* Start a Mac subprocess. Arguments for it is passed in argv (null
1979 terminated). The process should run with the default directory
1980 "workdir", read input from "infn", and write output and error to
1981 "outfn" and "errfn", resp. The Process Manager call
1982 LaunchApplication is used to start the subprocess. We use high
1983 level events as the mechanism to pass arguments to the subprocess
1984 and to make Emacs wait for the subprocess to terminate and pass
1985 back a result code. The bulk of the code here packs the arguments
1986 into one message to be passed together with the high level event.
1987 Emacs also sometimes starts a subprocess using a shell to perform
1988 wildcard filename expansion. Since we don't really have a shell on
1989 the Mac, this case is detected and the starting of the shell is
1990 by-passed. We really need to add code here to do filename
1991 expansion to support such functionality. */
1994 run_mac_command (argv, workdir, infn, outfn, errfn)
1995 unsigned char **argv;
1996 const char *workdir;
1997 const char *infn, *outfn, *errfn;
1999 #ifdef TARGET_API_MAC_CARBON
2000 return -1;
2001 #else /* not TARGET_API_MAC_CARBON */
2002 char macappname[MAXPATHLEN+1], macworkdir[MAXPATHLEN+1];
2003 char macinfn[MAXPATHLEN+1], macoutfn[MAXPATHLEN+1], macerrfn[MAXPATHLEN+1];
2004 int paramlen, argc, newargc, j, retries;
2005 char **newargv, *param, *p;
2006 OSErr iErr;
2007 FSSpec spec;
2008 LaunchParamBlockRec lpbr;
2009 EventRecord send_event, reply_event;
2010 RgnHandle cursor_region_handle;
2011 TargetID targ;
2012 unsigned long ref_con, len;
2014 if (posix_to_mac_pathname (workdir, macworkdir, MAXPATHLEN+1) == 0)
2015 return -1;
2016 if (posix_to_mac_pathname (infn, macinfn, MAXPATHLEN+1) == 0)
2017 return -1;
2018 if (posix_to_mac_pathname (outfn, macoutfn, MAXPATHLEN+1) == 0)
2019 return -1;
2020 if (posix_to_mac_pathname (errfn, macerrfn, MAXPATHLEN+1) == 0)
2021 return -1;
2023 paramlen = strlen (macworkdir) + strlen (macinfn) + strlen (macoutfn)
2024 + strlen (macerrfn) + 4; /* count nulls at end of strings */
2026 argc = 0;
2027 while (argv[argc])
2028 argc++;
2030 if (argc == 0)
2031 return -1;
2033 /* If a subprocess is invoked with a shell, we receive 3 arguments
2034 of the form: "<path to emacs bins>/sh" "-c" "<path to emacs
2035 bins>/<command> <command args>" */
2036 j = strlen (argv[0]);
2037 if (j >= 3 && strcmp (argv[0]+j-3, "/sh") == 0
2038 && argc == 3 && strcmp (argv[1], "-c") == 0)
2040 char *command, *t, tempmacpathname[MAXPATHLEN+1];
2042 /* The arguments for the command in argv[2] are separated by
2043 spaces. Count them and put the count in newargc. */
2044 command = (char *) alloca (strlen (argv[2])+2);
2045 strcpy (command, argv[2]);
2046 if (command[strlen (command) - 1] != ' ')
2047 strcat (command, " ");
2049 t = command;
2050 newargc = 0;
2051 t = mystrchr (t, ' ');
2052 while (t)
2054 newargc++;
2055 t = mystrchr (t+1, ' ');
2058 newargv = (char **) alloca (sizeof (char *) * newargc);
2060 t = command;
2061 for (j = 0; j < newargc; j++)
2063 newargv[j] = (char *) alloca (strlen (t) + 1);
2064 mystrcpy (newargv[j], t);
2066 t = mystrtok (t);
2067 paramlen += strlen (newargv[j]) + 1;
2070 if (strncmp (newargv[0], "~emacs/", 7) == 0)
2072 if (posix_to_mac_pathname (newargv[0], tempmacpathname, MAXPATHLEN+1)
2073 == 0)
2074 return -1;
2076 else
2077 { /* sometimes Emacs call "sh" without a path for the command */
2078 #if 0
2079 char *t = (char *) alloca (strlen (newargv[0]) + 7 + 1);
2080 strcpy (t, "~emacs/");
2081 strcat (t, newargv[0]);
2082 #endif /* 0 */
2083 Lisp_Object path;
2084 openp (Vexec_path, build_string (newargv[0]), EXEC_SUFFIXES, &path,
2085 make_number (X_OK));
2087 if (NILP (path))
2088 return -1;
2089 if (posix_to_mac_pathname (SDATA (path), tempmacpathname,
2090 MAXPATHLEN+1) == 0)
2091 return -1;
2093 strcpy (macappname, tempmacpathname);
2095 else
2097 if (posix_to_mac_pathname (argv[0], macappname, MAXPATHLEN+1) == 0)
2098 return -1;
2100 newargv = (char **) alloca (sizeof (char *) * argc);
2101 newargc = argc;
2102 for (j = 1; j < argc; j++)
2104 if (strncmp (argv[j], "~emacs/", 7) == 0)
2106 char *t = strchr (argv[j], ' ');
2107 if (t)
2109 char tempcmdname[MAXPATHLEN+1], tempmaccmdname[MAXPATHLEN+1];
2110 strncpy (tempcmdname, argv[j], t-argv[j]);
2111 tempcmdname[t-argv[j]] = '\0';
2112 if (posix_to_mac_pathname (tempcmdname, tempmaccmdname,
2113 MAXPATHLEN+1) == 0)
2114 return -1;
2115 newargv[j] = (char *) alloca (strlen (tempmaccmdname)
2116 + strlen (t) + 1);
2117 strcpy (newargv[j], tempmaccmdname);
2118 strcat (newargv[j], t);
2120 else
2122 char tempmaccmdname[MAXPATHLEN+1];
2123 if (posix_to_mac_pathname (argv[j], tempmaccmdname,
2124 MAXPATHLEN+1) == 0)
2125 return -1;
2126 newargv[j] = (char *) alloca (strlen (tempmaccmdname)+1);
2127 strcpy (newargv[j], tempmaccmdname);
2130 else
2131 newargv[j] = argv[j];
2132 paramlen += strlen (newargv[j]) + 1;
2136 /* After expanding all the arguments, we now know the length of the
2137 parameter block to be sent to the subprocess as a message
2138 attached to the HLE. */
2139 param = (char *) malloc (paramlen + 1);
2140 if (!param)
2141 return -1;
2143 p = param;
2144 *p++ = newargc;
2145 /* first byte of message contains number of arguments for command */
2146 strcpy (p, macworkdir);
2147 p += strlen (macworkdir);
2148 *p++ = '\0';
2149 /* null terminate strings sent so it's possible to use strcpy over there */
2150 strcpy (p, macinfn);
2151 p += strlen (macinfn);
2152 *p++ = '\0';
2153 strcpy (p, macoutfn);
2154 p += strlen (macoutfn);
2155 *p++ = '\0';
2156 strcpy (p, macerrfn);
2157 p += strlen (macerrfn);
2158 *p++ = '\0';
2159 for (j = 1; j < newargc; j++)
2161 strcpy (p, newargv[j]);
2162 p += strlen (newargv[j]);
2163 *p++ = '\0';
2166 c2pstr (macappname);
2168 iErr = FSMakeFSSpec (0, 0, macappname, &spec);
2170 if (iErr != noErr)
2172 free (param);
2173 return -1;
2176 lpbr.launchBlockID = extendedBlock;
2177 lpbr.launchEPBLength = extendedBlockLen;
2178 lpbr.launchControlFlags = launchContinue + launchNoFileFlags;
2179 lpbr.launchAppSpec = &spec;
2180 lpbr.launchAppParameters = NULL;
2182 iErr = LaunchApplication (&lpbr); /* call the subprocess */
2183 if (iErr != noErr)
2185 free (param);
2186 return -1;
2189 send_event.what = kHighLevelEvent;
2190 send_event.message = kEmacsSubprocessSend;
2191 /* Event ID stored in "where" unused */
2193 retries = 3;
2194 /* OS may think current subprocess has terminated if previous one
2195 terminated recently. */
2198 iErr = PostHighLevelEvent (&send_event, &lpbr.launchProcessSN, 0, param,
2199 paramlen + 1, receiverIDisPSN);
2201 while (iErr == sessClosedErr && retries-- > 0);
2203 if (iErr != noErr)
2205 free (param);
2206 return -1;
2209 cursor_region_handle = NewRgn ();
2211 /* Wait for the subprocess to finish, when it will send us a ERPY
2212 high level event. */
2213 while (1)
2214 if (WaitNextEvent (highLevelEventMask, &reply_event, 180,
2215 cursor_region_handle)
2216 && reply_event.message == kEmacsSubprocessReply)
2217 break;
2219 /* The return code is sent through the refCon */
2220 iErr = AcceptHighLevelEvent (&targ, &ref_con, NULL, &len);
2221 if (iErr != noErr)
2223 DisposeHandle ((Handle) cursor_region_handle);
2224 free (param);
2225 return -1;
2228 DisposeHandle ((Handle) cursor_region_handle);
2229 free (param);
2231 return ref_con;
2232 #endif /* not TARGET_API_MAC_CARBON */
2236 DIR *
2237 opendir (const char *dirname)
2239 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
2240 char mac_pathname[MAXPATHLEN+1], vol_name[MAXPATHLEN+1];
2241 DIR *dirp;
2242 CInfoPBRec cipb;
2243 HVolumeParam vpb;
2244 int len, vol_name_len;
2246 if (find_true_pathname (dirname, true_pathname, MAXPATHLEN+1) == -1)
2247 return 0;
2249 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
2250 if (len > -1)
2251 fully_resolved_name[len] = '\0';
2252 else
2253 strcpy (fully_resolved_name, true_pathname);
2255 dirp = (DIR *) malloc (sizeof(DIR));
2256 if (!dirp)
2257 return 0;
2259 /* Handle special case when dirname is "/": sets up for readir to
2260 get all mount volumes. */
2261 if (strcmp (fully_resolved_name, "/") == 0)
2263 dirp->getting_volumes = 1; /* special all mounted volumes DIR struct */
2264 dirp->current_index = 1; /* index for first volume */
2265 return dirp;
2268 /* Handle typical cases: not accessing all mounted volumes. */
2269 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
2270 return 0;
2272 /* Emacs calls opendir without the trailing '/', Mac needs trailing ':' */
2273 len = strlen (mac_pathname);
2274 if (mac_pathname[len - 1] != ':' && len < MAXPATHLEN)
2275 strcat (mac_pathname, ":");
2277 /* Extract volume name */
2278 vol_name_len = strchr (mac_pathname, ':') - mac_pathname;
2279 strncpy (vol_name, mac_pathname, vol_name_len);
2280 vol_name[vol_name_len] = '\0';
2281 strcat (vol_name, ":");
2283 c2pstr (mac_pathname);
2284 cipb.hFileInfo.ioNamePtr = mac_pathname;
2285 /* using full pathname so vRefNum and DirID ignored */
2286 cipb.hFileInfo.ioVRefNum = 0;
2287 cipb.hFileInfo.ioDirID = 0;
2288 cipb.hFileInfo.ioFDirIndex = 0;
2289 /* set to 0 to get information about specific dir or file */
2291 errno = PBGetCatInfo (&cipb, false);
2292 if (errno != noErr)
2294 errno = ENOENT;
2295 return 0;
2298 if (!(cipb.hFileInfo.ioFlAttrib & 0x10)) /* bit 4 = 1 for directories */
2299 return 0; /* not a directory */
2301 dirp->dir_id = cipb.dirInfo.ioDrDirID; /* used later in readdir */
2302 dirp->getting_volumes = 0;
2303 dirp->current_index = 1; /* index for first file/directory */
2305 c2pstr (vol_name);
2306 vpb.ioNamePtr = vol_name;
2307 /* using full pathname so vRefNum and DirID ignored */
2308 vpb.ioVRefNum = 0;
2309 vpb.ioVolIndex = -1;
2310 errno = PBHGetVInfo ((union HParamBlockRec *) &vpb, false);
2311 if (errno != noErr)
2313 errno = ENOENT;
2314 return 0;
2317 dirp->vol_ref_num = vpb.ioVRefNum;
2319 return dirp;
2323 closedir (DIR *dp)
2325 free (dp);
2327 return 0;
2331 struct dirent *
2332 readdir (DIR *dp)
2334 HParamBlockRec hpblock;
2335 CInfoPBRec cipb;
2336 static struct dirent s_dirent;
2337 static Str255 s_name;
2338 int done;
2339 char *p;
2341 /* Handle the root directory containing the mounted volumes. Call
2342 PBHGetVInfo specifying an index to obtain the info for a volume.
2343 PBHGetVInfo returns an error when it receives an index beyond the
2344 last volume, at which time we should return a nil dirent struct
2345 pointer. */
2346 if (dp->getting_volumes)
2348 hpblock.volumeParam.ioNamePtr = s_name;
2349 hpblock.volumeParam.ioVRefNum = 0;
2350 hpblock.volumeParam.ioVolIndex = dp->current_index;
2352 errno = PBHGetVInfo (&hpblock, false);
2353 if (errno != noErr)
2355 errno = ENOENT;
2356 return 0;
2359 p2cstr (s_name);
2360 strcat (s_name, "/"); /* need "/" for stat to work correctly */
2362 dp->current_index++;
2364 s_dirent.d_ino = hpblock.volumeParam.ioVRefNum;
2365 s_dirent.d_name = s_name;
2367 return &s_dirent;
2369 else
2371 cipb.hFileInfo.ioVRefNum = dp->vol_ref_num;
2372 cipb.hFileInfo.ioNamePtr = s_name;
2373 /* location to receive filename returned */
2375 /* return only visible files */
2376 done = false;
2377 while (!done)
2379 cipb.hFileInfo.ioDirID = dp->dir_id;
2380 /* directory ID found by opendir */
2381 cipb.hFileInfo.ioFDirIndex = dp->current_index;
2383 errno = PBGetCatInfo (&cipb, false);
2384 if (errno != noErr)
2386 errno = ENOENT;
2387 return 0;
2390 /* insist on a visible entry */
2391 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* directory? */
2392 done = !(cipb.dirInfo.ioDrUsrWds.frFlags & fInvisible);
2393 else
2394 done = !(cipb.hFileInfo.ioFlFndrInfo.fdFlags & fInvisible);
2396 dp->current_index++;
2399 p2cstr (s_name);
2401 p = s_name;
2402 while (*p)
2404 if (*p == '/')
2405 *p = ':';
2406 p++;
2409 s_dirent.d_ino = cipb.dirInfo.ioDrDirID;
2410 /* value unimportant: non-zero for valid file */
2411 s_dirent.d_name = s_name;
2413 return &s_dirent;
2418 char *
2419 getwd (char *path)
2421 char mac_pathname[MAXPATHLEN+1];
2422 Str255 directory_name;
2423 OSErr errno;
2424 CInfoPBRec cipb;
2426 if (path_from_vol_dir_name (mac_pathname, 255, 0, 0, "\p") == 0)
2427 return NULL;
2429 if (mac_to_posix_pathname (mac_pathname, path, MAXPATHLEN+1) == 0)
2430 return 0;
2431 else
2432 return path;
2435 #endif /* ! MAC_OSX */
2438 void
2439 initialize_applescript ()
2441 AEDesc null_desc;
2442 OSAError osaerror;
2444 /* if open fails, as_scripting_component is set to NULL. Its
2445 subsequent use in OSA calls will fail with badComponentInstance
2446 error. */
2447 as_scripting_component = OpenDefaultComponent (kOSAComponentType,
2448 kAppleScriptSubtype);
2450 null_desc.descriptorType = typeNull;
2451 null_desc.dataHandle = 0;
2452 osaerror = OSAMakeContext (as_scripting_component, &null_desc,
2453 kOSANullScript, &as_script_context);
2454 if (osaerror)
2455 as_script_context = kOSANullScript;
2456 /* use default context if create fails */
2460 void terminate_applescript()
2462 OSADispose (as_scripting_component, as_script_context);
2463 CloseComponent (as_scripting_component);
2467 /* Compile and execute the AppleScript SCRIPT and return the error
2468 status as function value. A zero is returned if compilation and
2469 execution is successful, in which case RESULT returns a pointer to
2470 a string containing the resulting script value. Otherwise, the Mac
2471 error code is returned and RESULT returns a pointer to an error
2472 string. In both cases the caller should deallocate the storage
2473 used by the string pointed to by RESULT if it is non-NULL. For
2474 documentation on the MacOS scripting architecture, see Inside
2475 Macintosh - Interapplication Communications: Scripting Components. */
2477 static long
2478 do_applescript (char *script, char **result)
2480 AEDesc script_desc, result_desc, error_desc;
2481 OSErr error;
2482 OSAError osaerror;
2483 long length;
2485 *result = 0;
2487 if (!as_scripting_component)
2488 initialize_applescript();
2490 error = AECreateDesc (typeChar, script, strlen(script), &script_desc);
2491 if (error)
2492 return error;
2494 osaerror = OSADoScript (as_scripting_component, &script_desc, kOSANullScript,
2495 typeChar, kOSAModeNull, &result_desc);
2497 if (osaerror == errOSAScriptError)
2499 /* error executing AppleScript: retrieve error message */
2500 if (!OSAScriptError (as_scripting_component, kOSAErrorMessage, typeChar,
2501 &error_desc))
2503 #if TARGET_API_MAC_CARBON
2504 length = AEGetDescDataSize (&error_desc);
2505 *result = (char *) xmalloc (length + 1);
2506 if (*result)
2508 AEGetDescData (&error_desc, *result, length);
2509 *(*result + length) = '\0';
2511 #else /* not TARGET_API_MAC_CARBON */
2512 HLock (error_desc.dataHandle);
2513 length = GetHandleSize(error_desc.dataHandle);
2514 *result = (char *) xmalloc (length + 1);
2515 if (*result)
2517 memcpy (*result, *(error_desc.dataHandle), length);
2518 *(*result + length) = '\0';
2520 HUnlock (error_desc.dataHandle);
2521 #endif /* not TARGET_API_MAC_CARBON */
2522 AEDisposeDesc (&error_desc);
2525 else if (osaerror == noErr) /* success: retrieve resulting script value */
2527 #if TARGET_API_MAC_CARBON
2528 length = AEGetDescDataSize (&result_desc);
2529 *result = (char *) xmalloc (length + 1);
2530 if (*result)
2532 AEGetDescData (&result_desc, *result, length);
2533 *(*result + length) = '\0';
2535 #else /* not TARGET_API_MAC_CARBON */
2536 HLock (result_desc.dataHandle);
2537 length = GetHandleSize(result_desc.dataHandle);
2538 *result = (char *) xmalloc (length + 1);
2539 if (*result)
2541 memcpy (*result, *(result_desc.dataHandle), length);
2542 *(*result + length) = '\0';
2544 HUnlock (result_desc.dataHandle);
2545 #endif /* not TARGET_API_MAC_CARBON */
2546 AEDisposeDesc (&result_desc);
2549 AEDisposeDesc (&script_desc);
2551 return osaerror;
2555 DEFUN ("do-applescript", Fdo_applescript, Sdo_applescript, 1, 1, 0,
2556 doc: /* Compile and execute AppleScript SCRIPT and retrieve and return the result.
2557 If compilation and execution are successful, the resulting script
2558 value is returned as a string. Otherwise the function aborts and
2559 displays the error message returned by the AppleScript scripting
2560 component. */)
2561 (script)
2562 Lisp_Object script;
2564 char *result, *temp;
2565 Lisp_Object lisp_result;
2566 long status;
2568 CHECK_STRING (script);
2570 BLOCK_INPUT;
2571 status = do_applescript (SDATA (script), &result);
2572 UNBLOCK_INPUT;
2573 if (status)
2575 if (!result)
2576 error ("AppleScript error %d", status);
2577 else
2579 /* Unfortunately only OSADoScript in do_applescript knows how
2580 how large the resulting script value or error message is
2581 going to be and therefore as caller memory must be
2582 deallocated here. It is necessary to free the error
2583 message before calling error to avoid a memory leak. */
2584 temp = (char *) alloca (strlen (result) + 1);
2585 strcpy (temp, result);
2586 xfree (result);
2587 error (temp);
2590 else
2592 lisp_result = build_string (result);
2593 xfree (result);
2594 return lisp_result;
2599 DEFUN ("mac-file-name-to-posix", Fmac_file_name_to_posix,
2600 Smac_file_name_to_posix, 1, 1, 0,
2601 doc: /* Convert Macintosh filename to Posix form. */)
2602 (mac_filename)
2603 Lisp_Object mac_filename;
2605 char posix_filename[MAXPATHLEN+1];
2607 CHECK_STRING (mac_filename);
2609 if (mac_to_posix_pathname (SDATA (mac_filename), posix_filename,
2610 MAXPATHLEN))
2611 return build_string (posix_filename);
2612 else
2613 return Qnil;
2617 DEFUN ("posix-file-name-to-mac", Fposix_file_name_to_mac,
2618 Sposix_file_name_to_mac, 1, 1, 0,
2619 doc: /* Convert Posix filename to Mac form. */)
2620 (posix_filename)
2621 Lisp_Object posix_filename;
2623 char mac_filename[MAXPATHLEN+1];
2625 CHECK_STRING (posix_filename);
2627 if (posix_to_mac_pathname (SDATA (posix_filename), mac_filename,
2628 MAXPATHLEN))
2629 return build_string (mac_filename);
2630 else
2631 return Qnil;
2635 /* set interprogram-paste-function to mac-paste-function in mac-win.el
2636 to enable Emacs to obtain the contents of the Mac clipboard. */
2637 DEFUN ("mac-paste-function", Fmac_paste_function, Smac_paste_function, 0, 0, 0,
2638 doc: /* Return the contents of the Mac clipboard as a string. */)
2641 #if TARGET_API_MAC_CARBON
2642 OSStatus err;
2643 ScrapRef scrap;
2644 ScrapFlavorFlags sff;
2645 Size s;
2646 int i;
2647 char *data;
2649 BLOCK_INPUT;
2650 err = GetCurrentScrap (&scrap);
2651 if (err == noErr)
2652 err = GetScrapFlavorFlags (scrap, kScrapFlavorTypeText, &sff);
2653 if (err == noErr)
2654 err = GetScrapFlavorSize (scrap, kScrapFlavorTypeText, &s);
2655 if (err == noErr && (data = (char*) alloca (s)))
2656 err = GetScrapFlavorData (scrap, kScrapFlavorTypeText, &s, data);
2657 UNBLOCK_INPUT;
2658 if (err != noErr || s == 0)
2659 return Qnil;
2661 /* Emacs expects clipboard contents have Unix-style eol's */
2662 for (i = 0; i < s; i++)
2663 if (data[i] == '\r')
2664 data[i] = '\n';
2666 return make_string (data, s);
2667 #else /* not TARGET_API_MAC_CARBON */
2668 Lisp_Object value;
2669 Handle my_handle;
2670 long scrap_offset, rc, i;
2672 my_handle = NewHandle (0); /* allocate 0-length data area */
2674 rc = GetScrap (my_handle, 'TEXT', &scrap_offset);
2675 if (rc < 0)
2676 return Qnil;
2678 HLock (my_handle);
2680 /* Emacs expects clipboard contents have Unix-style eol's */
2681 for (i = 0; i < rc; i++)
2682 if ((*my_handle)[i] == '\r')
2683 (*my_handle)[i] = '\n';
2685 value = make_string (*my_handle, rc);
2687 HUnlock (my_handle);
2689 DisposeHandle (my_handle);
2691 return value;
2692 #endif /* not TARGET_API_MAC_CARBON */
2696 /* set interprogram-cut-function to mac-cut-function in mac-win.el
2697 to enable Emacs to write the top of the kill-ring to the Mac clipboard. */
2698 DEFUN ("mac-cut-function", Fmac_cut_function, Smac_cut_function, 1, 2, 0,
2699 doc: /* Put the value of the string parameter to the Mac clipboard. */)
2700 (value, push)
2701 Lisp_Object value, push;
2703 char *buf;
2704 int len, i;
2706 /* fixme: ignore the push flag for now */
2708 CHECK_STRING (value);
2710 len = SCHARS (value);
2711 buf = (char *) alloca (len+1);
2712 bcopy (SDATA (value), buf, len);
2713 buf[len] = '\0';
2715 /* convert to Mac-style eol's before sending to clipboard */
2716 for (i = 0; i < len; i++)
2717 if (buf[i] == '\n')
2718 buf[i] = '\r';
2720 #if TARGET_API_MAC_CARBON
2722 ScrapRef scrap;
2724 BLOCK_INPUT;
2725 ClearCurrentScrap ();
2726 if (GetCurrentScrap (&scrap) != noErr)
2728 UNBLOCK_INPUT;
2729 error ("cannot get current scrap");
2732 if (PutScrapFlavor (scrap, kScrapFlavorTypeText, kScrapFlavorMaskNone, len,
2733 buf) != noErr)
2735 UNBLOCK_INPUT;
2736 error ("cannot put to scrap");
2738 UNBLOCK_INPUT;
2740 #else /* not TARGET_API_MAC_CARBON */
2741 ZeroScrap ();
2742 PutScrap (len, 'TEXT', buf);
2743 #endif /* not TARGET_API_MAC_CARBON */
2745 return Qnil;
2749 DEFUN ("x-selection-exists-p", Fx_selection_exists_p, Sx_selection_exists_p,
2750 0, 1, 0,
2751 doc: /* Whether there is an owner for the given X Selection.
2752 The arg should be the name of the selection in question, typically one of
2753 the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.
2754 \(Those are literal upper-case symbol names, since that's what X expects.)
2755 For convenience, the symbol nil is the same as `PRIMARY',
2756 and t is the same as `SECONDARY'. */)
2757 (selection)
2758 Lisp_Object selection;
2760 CHECK_SYMBOL (selection);
2762 /* Return nil for PRIMARY and SECONDARY selections; for CLIPBOARD, check
2763 if the clipboard currently has valid text format contents. */
2765 if (EQ (selection, QCLIPBOARD))
2767 Lisp_Object val = Qnil;
2769 #if TARGET_API_MAC_CARBON
2770 ScrapRef scrap;
2771 ScrapFlavorFlags sff;
2773 BLOCK_INPUT;
2774 if (GetCurrentScrap (&scrap) == noErr)
2775 if (GetScrapFlavorFlags (scrap, kScrapFlavorTypeText, &sff) == noErr)
2776 val = Qt;
2777 UNBLOCK_INPUT;
2778 #else /* not TARGET_API_MAC_CARBON */
2779 Handle my_handle;
2780 long rc, scrap_offset;
2782 my_handle = NewHandle (0);
2784 rc = GetScrap (my_handle, 'TEXT', &scrap_offset);
2785 if (rc >= 0)
2786 val = Qt;
2788 DisposeHandle (my_handle);
2789 #endif /* not TARGET_API_MAC_CARBON */
2791 return val;
2793 return Qnil;
2796 #ifdef MAC_OSX
2797 #undef select
2799 extern int inhibit_window_system;
2800 extern int noninteractive;
2802 /* When Emacs is started from the Finder, SELECT always immediately
2803 returns as if input is present when file descriptor 0 is polled for
2804 input. Strangely, when Emacs is run as a GUI application from the
2805 command line, it blocks in the same situation. This `wrapper' of
2806 the system call SELECT corrects this discrepancy. */
2808 sys_select (n, rfds, wfds, efds, timeout)
2809 int n;
2810 SELECT_TYPE *rfds;
2811 SELECT_TYPE *wfds;
2812 SELECT_TYPE *efds;
2813 struct timeval *timeout;
2815 OSErr err;
2816 EMACS_TIME end_time, now, remaining_time;
2818 if (inhibit_window_system || noninteractive
2819 || rfds == NULL || !FD_ISSET (0, rfds))
2820 return select (n, rfds, wfds, efds, timeout);
2822 if (wfds == NULL && efds == NULL)
2824 int i;
2826 for (i = 1; i < n; i++)
2827 if (FD_ISSET (i, rfds))
2828 break;
2829 if (i == n)
2831 EventTimeout timeout_sec =
2832 (timeout
2833 ? (EMACS_SECS (*timeout) * kEventDurationSecond
2834 + EMACS_USECS (*timeout) * kEventDurationMicrosecond)
2835 : kEventDurationForever);
2837 BLOCK_INPUT;
2838 err = ReceiveNextEvent (0, NULL, timeout_sec,
2839 kEventLeaveInQueue, NULL);
2840 UNBLOCK_INPUT;
2841 if (err == noErr)
2843 FD_ZERO (rfds);
2844 FD_SET (0, rfds);
2845 return 1;
2847 else
2848 return 0;
2852 if (timeout)
2854 remaining_time = *timeout;
2855 EMACS_GET_TIME (now);
2856 EMACS_ADD_TIME (end_time, now, remaining_time);
2858 FD_CLR (0, rfds);
2861 EMACS_TIME select_timeout;
2862 SELECT_TYPE orfds = *rfds;
2863 int r;
2865 EMACS_SET_SECS_USECS (select_timeout, 0, 20000);
2867 if (timeout && EMACS_TIME_LT (remaining_time, select_timeout))
2868 select_timeout = remaining_time;
2870 r = select (n, &orfds, wfds, efds, &select_timeout);
2871 BLOCK_INPUT;
2872 err = ReceiveNextEvent (0, NULL, kEventDurationNoWait,
2873 kEventLeaveInQueue, NULL);
2874 UNBLOCK_INPUT;
2875 if (r > 0)
2877 *rfds = orfds;
2878 if (err == noErr)
2880 FD_SET (0, rfds);
2881 r++;
2883 return r;
2885 else if (err == noErr)
2887 FD_ZERO (rfds);
2888 FD_SET (0, rfds);
2889 return 1;
2892 if (timeout)
2894 EMACS_GET_TIME (now);
2895 EMACS_SUB_TIME (remaining_time, end_time, now);
2898 while (!timeout || EMACS_TIME_LT (now, end_time));
2900 return 0;
2903 /* Set up environment variables so that Emacs can correctly find its
2904 support files when packaged as an application bundle. Directories
2905 placed in /usr/local/share/emacs/<emacs-version>/, /usr/local/bin,
2906 and /usr/local/libexec/emacs/<emacs-version>/<system-configuration>
2907 by `make install' by default can instead be placed in
2908 .../Emacs.app/Contents/Resources/ and
2909 .../Emacs.app/Contents/MacOS/. Each of these environment variables
2910 is changed only if it is not already set. Presumably if the user
2911 sets an environment variable, he will want to use files in his path
2912 instead of ones in the application bundle. */
2913 void
2914 init_mac_osx_environment ()
2916 CFBundleRef bundle;
2917 CFURLRef bundleURL;
2918 CFStringRef cf_app_bundle_pathname;
2919 int app_bundle_pathname_len;
2920 char *app_bundle_pathname;
2921 char *p, *q;
2922 struct stat st;
2924 /* Fetch the pathname of the application bundle as a C string into
2925 app_bundle_pathname. */
2927 bundle = CFBundleGetMainBundle ();
2928 if (!bundle)
2929 return;
2931 bundleURL = CFBundleCopyBundleURL (bundle);
2932 if (!bundleURL)
2933 return;
2935 cf_app_bundle_pathname = CFURLCopyFileSystemPath (bundleURL,
2936 kCFURLPOSIXPathStyle);
2937 app_bundle_pathname_len = CFStringGetLength (cf_app_bundle_pathname);
2938 app_bundle_pathname = (char *) alloca (app_bundle_pathname_len + 1);
2940 if (!CFStringGetCString (cf_app_bundle_pathname,
2941 app_bundle_pathname,
2942 app_bundle_pathname_len + 1,
2943 kCFStringEncodingISOLatin1))
2945 CFRelease (cf_app_bundle_pathname);
2946 return;
2949 CFRelease (cf_app_bundle_pathname);
2951 /* P should have sufficient room for the pathname of the bundle plus
2952 the subpath in it leading to the respective directories. Q
2953 should have three times that much room because EMACSLOADPATH can
2954 have the value "<path to lisp dir>:<path to leim dir>:<path to
2955 site-lisp dir>". */
2956 p = (char *) alloca (app_bundle_pathname_len + 50);
2957 q = (char *) alloca (3 * app_bundle_pathname_len + 150);
2958 if (!getenv ("EMACSLOADPATH"))
2960 q[0] = '\0';
2962 strcpy (p, app_bundle_pathname);
2963 strcat (p, "/Contents/Resources/lisp");
2964 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
2965 strcat (q, p);
2967 strcpy (p, app_bundle_pathname);
2968 strcat (p, "/Contents/Resources/leim");
2969 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
2971 if (q[0] != '\0')
2972 strcat (q, ":");
2973 strcat (q, p);
2976 strcpy (p, app_bundle_pathname);
2977 strcat (p, "/Contents/Resources/site-lisp");
2978 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
2980 if (q[0] != '\0')
2981 strcat (q, ":");
2982 strcat (q, p);
2985 if (q[0] != '\0')
2986 setenv ("EMACSLOADPATH", q, 1);
2989 if (!getenv ("EMACSPATH"))
2991 q[0] = '\0';
2993 strcpy (p, app_bundle_pathname);
2994 strcat (p, "/Contents/MacOS/libexec");
2995 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
2996 strcat (q, p);
2998 strcpy (p, app_bundle_pathname);
2999 strcat (p, "/Contents/MacOS/bin");
3000 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
3002 if (q[0] != '\0')
3003 strcat (q, ":");
3004 strcat (q, p);
3007 if (q[0] != '\0')
3008 setenv ("EMACSPATH", q, 1);
3011 if (!getenv ("EMACSDATA"))
3013 strcpy (p, app_bundle_pathname);
3014 strcat (p, "/Contents/Resources/etc");
3015 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
3016 setenv ("EMACSDATA", p, 1);
3019 if (!getenv ("EMACSDOC"))
3021 strcpy (p, app_bundle_pathname);
3022 strcat (p, "/Contents/Resources/etc");
3023 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
3024 setenv ("EMACSDOC", p, 1);
3027 if (!getenv ("INFOPATH"))
3029 strcpy (p, app_bundle_pathname);
3030 strcat (p, "/Contents/Resources/info");
3031 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
3032 setenv ("INFOPATH", p, 1);
3035 #endif /* MAC_OSX */
3037 void
3038 syms_of_mac ()
3040 QCLIPBOARD = intern ("CLIPBOARD");
3041 staticpro (&QCLIPBOARD);
3043 defsubr (&Smac_paste_function);
3044 defsubr (&Smac_cut_function);
3045 defsubr (&Sx_selection_exists_p);
3047 defsubr (&Sdo_applescript);
3048 defsubr (&Smac_file_name_to_posix);
3049 defsubr (&Sposix_file_name_to_mac);
3052 /* arch-tag: 29d30c1f-0c6b-4f88-8a6d-0558d7f9dbff
3053 (do not change this comment) */