2003-07-11 John Paul Wallington <jpw@gnu.org>
[emacs.git] / src / mac.c
blobce2e424249323d28bcae2a1b02b52340b408fd7f
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 <utime.h>
28 #include <dirent.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <string.h>
32 #include <pwd.h>
33 #include <sys/param.h>
34 #include <stdlib.h>
35 #include <fcntl.h>
36 #if __MWERKS__
37 #include <unistd.h>
38 #endif
40 #ifdef MAC_OSX
41 #undef mktime
42 #undef DEBUG
43 #undef free
44 #undef malloc
45 #undef realloc
46 #undef init_process
47 #include <Carbon/Carbon.h>
48 #undef free
49 #define free unexec_free
50 #undef malloc
51 #define malloc unexec_malloc
52 #undef realloc
53 #define realloc unexec_realloc
54 #undef init_process
55 #define init_process emacs_init_process
56 #else /* not MAC_OSX */
57 #include <Files.h>
58 #include <MacTypes.h>
59 #include <TextUtils.h>
60 #include <Folders.h>
61 #include <Resources.h>
62 #include <Aliases.h>
63 #include <FixMath.h>
64 #include <Timer.h>
65 #include <OSA.h>
66 #include <AppleScript.h>
67 #include <Scrap.h>
68 #endif /* not MAC_OSX */
70 #include "lisp.h"
71 #include "process.h"
72 #include "sysselect.h"
73 #include "systime.h"
75 Lisp_Object QCLIPBOARD;
77 /* An instance of the AppleScript component. */
78 static ComponentInstance as_scripting_component;
79 /* The single script context used for all script executions. */
80 static OSAID as_script_context;
83 /* When converting from Mac to Unix pathnames, /'s in folder names are
84 converted to :'s. This function, used in copying folder names,
85 performs a strncat and converts all character a to b in the copy of
86 the string s2 appended to the end of s1. */
88 void
89 string_cat_and_replace (char *s1, const char *s2, int n, char a, char b)
91 int l1 = strlen (s1);
92 int l2 = strlen (s2);
93 char *p = s1 + l1;
94 int i;
96 strncat (s1, s2, n);
97 for (i = 0; i < l2; i++)
99 if (*p == a)
100 *p = b;
101 p++;
106 /* Convert a Mac pathname to Posix form. A Mac full pathname is one
107 that does not begin with a ':' and contains at least one ':'. A Mac
108 full pathname causes a '/' to be prepended to the Posix pathname.
109 The algorithm for the rest of the pathname is as follows:
110 For each segment between two ':',
111 if it is non-null, copy as is and then add a '/' at the end,
112 otherwise, insert a "../" into the Posix pathname.
113 Returns 1 if successful; 0 if fails. */
116 mac_to_posix_pathname (const char *mfn, char *ufn, int ufnbuflen)
118 const char *p, *q, *pe;
120 strcpy (ufn, "");
122 if (*mfn == '\0')
123 return 1;
125 p = strchr (mfn, ':');
126 if (p != 0 && p != mfn) /* full pathname */
127 strcat (ufn, "/");
129 p = mfn;
130 if (*p == ':')
131 p++;
133 pe = mfn + strlen (mfn);
134 while (p < pe)
136 q = strchr (p, ':');
137 if (q)
139 if (q == p)
140 { /* two consecutive ':' */
141 if (strlen (ufn) + 3 >= ufnbuflen)
142 return 0;
143 strcat (ufn, "../");
145 else
147 if (strlen (ufn) + (q - p) + 1 >= ufnbuflen)
148 return 0;
149 string_cat_and_replace (ufn, p, q - p, '/', ':');
150 strcat (ufn, "/");
152 p = q + 1;
154 else
156 if (strlen (ufn) + (pe - p) >= ufnbuflen)
157 return 0;
158 string_cat_and_replace (ufn, p, pe - p, '/', ':');
159 /* no separator for last one */
160 p = pe;
164 return 1;
168 extern char *get_temp_dir_name ();
171 /* Convert a Posix pathname to Mac form. Approximately reverse of the
172 above in algorithm. */
175 posix_to_mac_pathname (const char *ufn, char *mfn, int mfnbuflen)
177 const char *p, *q, *pe;
178 char expanded_pathname[MAXPATHLEN+1];
180 strcpy (mfn, "");
182 if (*ufn == '\0')
183 return 1;
185 p = ufn;
187 /* Check for and handle volume names. Last comparison: strangely
188 somewhere "/.emacs" is passed. A temporary fix for now. */
189 if (*p == '/' && strchr (p+1, '/') == NULL && strcmp (p, "/.emacs") != 0)
191 if (strlen (p) + 1 > mfnbuflen)
192 return 0;
193 strcpy (mfn, p+1);
194 strcat (mfn, ":");
195 return 1;
198 /* expand to emacs dir found by init_emacs_passwd_dir */
199 if (strncmp (p, "~emacs/", 7) == 0)
201 struct passwd *pw = getpwnam ("emacs");
202 p += 7;
203 if (strlen (pw->pw_dir) + strlen (p) > MAXPATHLEN)
204 return 0;
205 strcpy (expanded_pathname, pw->pw_dir);
206 strcat (expanded_pathname, p);
207 p = expanded_pathname;
208 /* now p points to the pathname with emacs dir prefix */
210 else if (strncmp (p, "/tmp/", 5) == 0)
212 char *t = get_temp_dir_name ();
213 p += 5;
214 if (strlen (t) + strlen (p) > MAXPATHLEN)
215 return 0;
216 strcpy (expanded_pathname, t);
217 strcat (expanded_pathname, p);
218 p = expanded_pathname;
219 /* now p points to the pathname with emacs dir prefix */
221 else if (*p != '/') /* relative pathname */
222 strcat (mfn, ":");
224 if (*p == '/')
225 p++;
227 pe = p + strlen (p);
228 while (p < pe)
230 q = strchr (p, '/');
231 if (q)
233 if (q - p == 2 && *p == '.' && *(p+1) == '.')
235 if (strlen (mfn) + 1 >= mfnbuflen)
236 return 0;
237 strcat (mfn, ":");
239 else
241 if (strlen (mfn) + (q - p) + 1 >= mfnbuflen)
242 return 0;
243 string_cat_and_replace (mfn, p, q - p, ':', '/');
244 strcat (mfn, ":");
246 p = q + 1;
248 else
250 if (strlen (mfn) + (pe - p) >= mfnbuflen)
251 return 0;
252 string_cat_and_replace (mfn, p, pe - p, ':', '/');
253 p = pe;
257 return 1;
260 #ifndef MAC_OSX
262 /* The following functions with "sys_" prefix are stubs to Unix
263 functions that have already been implemented by CW or MPW. The
264 calls to them in Emacs source course are #define'd to call the sys_
265 versions by the header files s-mac.h. In these stubs pathnames are
266 converted between their Unix and Mac forms. */
269 /* Unix epoch is Jan 1, 1970 while Mac epoch is Jan 1, 1904: 66 years
270 + 17 leap days. These are for adjusting time values returned by
271 MacOS Toolbox functions. */
273 #define MAC_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
275 #ifdef __MWERKS__
276 #if __MSL__ < 0x6000
277 /* CW Pro 5 epoch is Jan 1, 1900 (aaarghhhhh!); remember, 1900 is not
278 a leap year! This is for adjusting time_t values returned by MSL
279 functions. */
280 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 70 + 17) * 24 * 60 * 60)
281 #else /* __MSL__ >= 0x6000 */
282 /* CW changes Pro 6 to follow Unix! */
283 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
284 #endif /* __MSL__ >= 0x6000 */
285 #elif __MRC__
286 /* MPW library functions follow Unix (confused?). */
287 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
288 #else /* not __MRC__ */
289 You lose!!!
290 #endif /* not __MRC__ */
293 /* Define our own stat function for both MrC and CW. The reason for
294 doing this: "stat" is both the name of a struct and function name:
295 can't use the same trick like that for sys_open, sys_close, etc. to
296 redirect Emacs's calls to our own version that converts Unix style
297 filenames to Mac style filename because all sorts of compilation
298 errors will be generated if stat is #define'd to be sys_stat. */
301 stat_noalias (const char *path, struct stat *buf)
303 char mac_pathname[MAXPATHLEN+1];
304 CInfoPBRec cipb;
306 if (posix_to_mac_pathname (path, mac_pathname, MAXPATHLEN+1) == 0)
307 return -1;
309 c2pstr (mac_pathname);
310 cipb.hFileInfo.ioNamePtr = mac_pathname;
311 cipb.hFileInfo.ioVRefNum = 0;
312 cipb.hFileInfo.ioDirID = 0;
313 cipb.hFileInfo.ioFDirIndex = 0;
314 /* set to 0 to get information about specific dir or file */
316 errno = PBGetCatInfo (&cipb, false);
317 if (errno == -43) /* -43: fnfErr defined in Errors.h */
318 errno = ENOENT;
319 if (errno != noErr)
320 return -1;
322 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* bit 4 = 1 for directories */
324 buf->st_mode = S_IFDIR | S_IREAD | S_IEXEC;
326 if (!(cipb.hFileInfo.ioFlAttrib & 0x1))
327 buf->st_mode |= S_IWRITE; /* bit 1 = 1 for locked files/directories */
328 buf->st_ino = cipb.dirInfo.ioDrDirID;
329 buf->st_dev = cipb.dirInfo.ioVRefNum;
330 buf->st_size = cipb.dirInfo.ioDrNmFls;
331 /* size of dir = number of files and dirs */
332 buf->st_atime
333 = buf->st_mtime
334 = cipb.dirInfo.ioDrMdDat - MAC_UNIX_EPOCH_DIFF;
335 buf->st_ctime = cipb.dirInfo.ioDrCrDat - MAC_UNIX_EPOCH_DIFF;
337 else
339 buf->st_mode = S_IFREG | S_IREAD;
340 if (!(cipb.hFileInfo.ioFlAttrib & 0x1))
341 buf->st_mode |= S_IWRITE; /* bit 1 = 1 for locked files/directories */
342 if (cipb.hFileInfo.ioFlFndrInfo.fdType == 'APPL')
343 buf->st_mode |= S_IEXEC;
344 buf->st_ino = cipb.hFileInfo.ioDirID;
345 buf->st_dev = cipb.hFileInfo.ioVRefNum;
346 buf->st_size = cipb.hFileInfo.ioFlLgLen;
347 buf->st_atime
348 = buf->st_mtime
349 = cipb.hFileInfo.ioFlMdDat - MAC_UNIX_EPOCH_DIFF;
350 buf->st_ctime = cipb.hFileInfo.ioFlCrDat - MAC_UNIX_EPOCH_DIFF;
353 if (cipb.hFileInfo.ioFlFndrInfo.fdFlags & 0x8000)
355 /* identify alias files as symlinks */
356 buf->st_mode &= ~S_IFREG;
357 buf->st_mode |= S_IFLNK;
360 buf->st_nlink = 1;
361 buf->st_uid = getuid ();
362 buf->st_gid = getgid ();
363 buf->st_rdev = 0;
365 return 0;
370 lstat (const char *path, struct stat *buf)
372 int result;
373 char true_pathname[MAXPATHLEN+1];
375 /* Try looking for the file without resolving aliases first. */
376 if ((result = stat_noalias (path, buf)) >= 0)
377 return result;
379 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
380 return -1;
382 return stat_noalias (true_pathname, buf);
387 stat (const char *path, struct stat *sb)
389 int result;
390 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
391 int len;
393 if ((result = stat_noalias (path, sb)) >= 0 &&
394 ! (sb->st_mode & S_IFLNK))
395 return result;
397 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
398 return -1;
400 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
401 if (len > -1)
403 fully_resolved_name[len] = '\0';
404 /* in fact our readlink terminates strings */
405 return lstat (fully_resolved_name, sb);
407 else
408 return lstat (true_pathname, sb);
412 #if __MRC__
413 /* CW defines fstat in stat.mac.c while MPW does not provide this
414 function. Without the information of how to get from a file
415 descriptor in MPW StdCLib to a Mac OS file spec, it should be hard
416 to implement this function. Fortunately, there is only one place
417 where this function is called in our configuration: in fileio.c,
418 where only the st_dev and st_ino fields are used to determine
419 whether two fildes point to different i-nodes to prevent copying
420 a file onto itself equal. What we have here probably needs
421 improvement. */
424 fstat (int fildes, struct stat *buf)
426 buf->st_dev = 0;
427 buf->st_ino = fildes;
428 buf->st_mode = S_IFREG; /* added by T.I. for the copy-file */
429 return 0; /* success */
431 #endif /* __MRC__ */
435 mkdir (const char *dirname, int mode)
437 #pragma unused(mode)
439 HFileParam hfpb;
440 char true_pathname[MAXPATHLEN+1], mac_pathname[MAXPATHLEN+1];
442 if (find_true_pathname (dirname, true_pathname, MAXPATHLEN+1) == -1)
443 return -1;
445 if (posix_to_mac_pathname (true_pathname, mac_pathname, MAXPATHLEN+1) == 0)
446 return -1;
448 c2pstr (mac_pathname);
449 hfpb.ioNamePtr = mac_pathname;
450 hfpb.ioVRefNum = 0; /* ignored unless name is invalid */
451 hfpb.ioDirID = 0; /* parent is the root */
453 errno = PBDirCreate ((HParmBlkPtr) &hfpb, false);
454 /* just return the Mac OSErr code for now */
455 return errno == noErr ? 0 : -1;
459 #undef rmdir
460 sys_rmdir (const char *dirname)
462 HFileParam hfpb;
463 char mac_pathname[MAXPATHLEN+1];
465 if (posix_to_mac_pathname (dirname, mac_pathname, MAXPATHLEN+1) == 0)
466 return -1;
468 c2pstr (mac_pathname);
469 hfpb.ioNamePtr = mac_pathname;
470 hfpb.ioVRefNum = 0; /* ignored unless name is invalid */
471 hfpb.ioDirID = 0; /* parent is the root */
473 errno = PBHDelete ((HParmBlkPtr) &hfpb, false);
474 return errno == noErr ? 0 : -1;
478 #ifdef __MRC__
479 /* No implementation yet. */
481 execvp (const char *path, ...)
483 return -1;
485 #endif /* __MRC__ */
489 utime (const char *path, const struct utimbuf *times)
491 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
492 int len;
493 char mac_pathname[MAXPATHLEN+1];
494 CInfoPBRec cipb;
496 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
497 return -1;
499 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
500 if (len > -1)
501 fully_resolved_name[len] = '\0';
502 else
503 strcpy (fully_resolved_name, true_pathname);
505 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
506 return -1;
508 c2pstr (mac_pathname);
509 cipb.hFileInfo.ioNamePtr = mac_pathname;
510 cipb.hFileInfo.ioVRefNum = 0;
511 cipb.hFileInfo.ioDirID = 0;
512 cipb.hFileInfo.ioFDirIndex = 0;
513 /* set to 0 to get information about specific dir or file */
515 errno = PBGetCatInfo (&cipb, false);
516 if (errno != noErr)
517 return -1;
519 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* bit 4 = 1 for directories */
521 if (times)
522 cipb.dirInfo.ioDrMdDat = times->modtime + MAC_UNIX_EPOCH_DIFF;
523 else
524 GetDateTime (&cipb.dirInfo.ioDrMdDat);
526 else
528 if (times)
529 cipb.hFileInfo.ioFlMdDat = times->modtime + MAC_UNIX_EPOCH_DIFF;
530 else
531 GetDateTime (&cipb.hFileInfo.ioFlMdDat);
534 errno = PBSetCatInfo (&cipb, false);
535 return errno == noErr ? 0 : -1;
539 #ifndef F_OK
540 #define F_OK 0
541 #endif
542 #ifndef X_OK
543 #define X_OK 1
544 #endif
545 #ifndef W_OK
546 #define W_OK 2
547 #endif
549 /* Like stat, but test for access mode in hfpb.ioFlAttrib */
551 access (const char *path, int mode)
553 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
554 int len;
555 char mac_pathname[MAXPATHLEN+1];
556 CInfoPBRec cipb;
558 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
559 return -1;
561 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
562 if (len > -1)
563 fully_resolved_name[len] = '\0';
564 else
565 strcpy (fully_resolved_name, true_pathname);
567 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
568 return -1;
570 c2pstr (mac_pathname);
571 cipb.hFileInfo.ioNamePtr = mac_pathname;
572 cipb.hFileInfo.ioVRefNum = 0;
573 cipb.hFileInfo.ioDirID = 0;
574 cipb.hFileInfo.ioFDirIndex = 0;
575 /* set to 0 to get information about specific dir or file */
577 errno = PBGetCatInfo (&cipb, false);
578 if (errno != noErr)
579 return -1;
581 if (mode == F_OK) /* got this far, file exists */
582 return 0;
584 if (mode & X_OK)
585 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* path refers to a directory */
586 return 0;
587 else
589 if (cipb.hFileInfo.ioFlFndrInfo.fdType == 'APPL')
590 return 0;
591 else
592 return -1;
595 if (mode & W_OK)
596 return (cipb.hFileInfo.ioFlAttrib & 0x1) ? -1 : 0;
597 /* don't allow if lock bit is on */
599 return -1;
603 #define DEV_NULL_FD 0x10000
605 #undef open
607 sys_open (const char *path, int oflag)
609 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
610 int len;
611 char mac_pathname[MAXPATHLEN+1];
613 if (strcmp (path, "/dev/null") == 0)
614 return DEV_NULL_FD; /* some bogus fd to be ignored in write */
616 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
617 return -1;
619 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
620 if (len > -1)
621 fully_resolved_name[len] = '\0';
622 else
623 strcpy (fully_resolved_name, true_pathname);
625 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
626 return -1;
627 else
629 #ifdef __MRC__
630 int res = open (mac_pathname, oflag);
631 /* if (oflag == O_WRONLY || oflag == O_RDWR) */
632 if (oflag & O_CREAT)
633 fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
634 return res;
635 #else /* not __MRC__ */
636 return open (mac_pathname, oflag);
637 #endif /* not __MRC__ */
642 #undef creat
644 sys_creat (const char *path, mode_t mode)
646 char true_pathname[MAXPATHLEN+1];
647 int len;
648 char mac_pathname[MAXPATHLEN+1];
650 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
651 return -1;
653 if (!posix_to_mac_pathname (true_pathname, mac_pathname, MAXPATHLEN+1))
654 return -1;
655 else
657 #ifdef __MRC__
658 int result = creat (mac_pathname);
659 fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
660 return result;
661 #else /* not __MRC__ */
662 return creat (mac_pathname, mode);
663 #endif /* not __MRC__ */
668 #undef unlink
670 sys_unlink (const char *path)
672 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
673 int len;
674 char mac_pathname[MAXPATHLEN+1];
676 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
677 return -1;
679 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
680 if (len > -1)
681 fully_resolved_name[len] = '\0';
682 else
683 strcpy (fully_resolved_name, true_pathname);
685 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
686 return -1;
687 else
688 return unlink (mac_pathname);
692 #undef read
694 sys_read (int fildes, char *buf, int count)
696 if (fildes == 0) /* this should not be used for console input */
697 return -1;
698 else
699 #if __MSL__ >= 0x6000
700 return _read (fildes, buf, count);
701 #else
702 return read (fildes, buf, count);
703 #endif
707 #undef write
709 sys_write (int fildes, const char *buf, int count)
711 if (fildes == DEV_NULL_FD)
712 return count;
713 else
714 #if __MSL__ >= 0x6000
715 return _write (fildes, buf, count);
716 #else
717 return write (fildes, buf, count);
718 #endif
722 #undef rename
724 sys_rename (const char * old_name, const char * new_name)
726 char true_old_pathname[MAXPATHLEN+1], true_new_pathname[MAXPATHLEN+1];
727 char fully_resolved_old_name[MAXPATHLEN+1];
728 int len;
729 char mac_old_name[MAXPATHLEN+1], mac_new_name[MAXPATHLEN+1];
731 if (find_true_pathname (old_name, true_old_pathname, MAXPATHLEN+1) == -1)
732 return -1;
734 len = readlink (true_old_pathname, fully_resolved_old_name, MAXPATHLEN);
735 if (len > -1)
736 fully_resolved_old_name[len] = '\0';
737 else
738 strcpy (fully_resolved_old_name, true_old_pathname);
740 if (find_true_pathname (new_name, true_new_pathname, MAXPATHLEN+1) == -1)
741 return -1;
743 if (strcmp (fully_resolved_old_name, true_new_pathname) == 0)
744 return 0;
746 if (!posix_to_mac_pathname (fully_resolved_old_name,
747 mac_old_name,
748 MAXPATHLEN+1))
749 return -1;
751 if (!posix_to_mac_pathname(true_new_pathname, mac_new_name, MAXPATHLEN+1))
752 return -1;
754 /* If a file with new_name already exists, rename deletes the old
755 file in Unix. CW version fails in these situation. So we add a
756 call to unlink here. */
757 (void) unlink (mac_new_name);
759 return rename (mac_old_name, mac_new_name);
763 #undef fopen
764 extern FILE *fopen (const char *name, const char *mode);
765 FILE *
766 sys_fopen (const char *name, const char *mode)
768 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
769 int len;
770 char mac_pathname[MAXPATHLEN+1];
772 if (find_true_pathname (name, true_pathname, MAXPATHLEN+1) == -1)
773 return 0;
775 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
776 if (len > -1)
777 fully_resolved_name[len] = '\0';
778 else
779 strcpy (fully_resolved_name, true_pathname);
781 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
782 return 0;
783 else
785 #ifdef __MRC__
786 if (mode[0] == 'w' || mode[0] == 'a')
787 fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
788 #endif /* not __MRC__ */
789 return fopen (mac_pathname, mode);
794 #include <Events.h>
796 long target_ticks = 0;
798 #ifdef __MRC__
799 __sigfun alarm_signal_func = (__sigfun) 0;
800 #elif __MWERKS__
801 __signal_func_ptr alarm_signal_func = (__signal_func_ptr) 0;
802 #else /* not __MRC__ and not __MWERKS__ */
803 You lose!!!
804 #endif /* not __MRC__ and not __MWERKS__ */
807 /* These functions simulate SIG_ALRM. The stub for function signal
808 stores the signal handler function in alarm_signal_func if a
809 SIG_ALRM is encountered. check_alarm is called in XTread_socket,
810 which emacs calls periodically. A pending alarm is represented by
811 a non-zero target_ticks value. check_alarm calls the handler
812 function pointed to by alarm_signal_func if one has been set up and
813 an alarm is pending. */
815 void
816 check_alarm ()
818 if (target_ticks && TickCount () > target_ticks)
820 target_ticks = 0;
821 if (alarm_signal_func)
822 (*alarm_signal_func)(SIGALRM);
828 select (n, rfds, wfds, efds, timeout)
829 int n;
830 SELECT_TYPE *rfds;
831 SELECT_TYPE *wfds;
832 SELECT_TYPE *efds;
833 struct timeval *timeout;
835 #ifdef TARGET_API_MAC_CARBON
836 return 1;
837 #else /* not TARGET_API_MAC_CARBON */
838 EMACS_TIME end_time, now;
839 EventRecord e;
841 /* Can only handle wait for keyboard input. */
842 if (n > 1 || wfds || efds)
843 return -1;
845 EMACS_GET_TIME (end_time);
846 EMACS_ADD_TIME (end_time, end_time, *timeout);
850 /* Also return true if an event other than a keyDown has
851 occurred. This causes kbd_buffer_get_event in keyboard.c to
852 call read_avail_input which in turn calls XTread_socket to
853 poll for these events. Otherwise these never get processed
854 except but a very slow poll timer. */
855 if (FD_ISSET (0, rfds) && EventAvail (everyEvent, &e))
856 return 1;
858 /* Also check movement of the mouse. */
860 Point mouse_pos;
861 static Point old_mouse_pos = {-1, -1};
863 GetMouse (&mouse_pos);
864 if (!EqualPt (mouse_pos, old_mouse_pos))
866 old_mouse_pos = mouse_pos;
867 return 1;
871 WaitNextEvent (0, &e, 1UL, NULL); /* Accept no event; wait 1
872 tic. by T.I. */
874 EMACS_GET_TIME (now);
875 EMACS_SUB_TIME (now, end_time, now);
877 while (!EMACS_TIME_NEG_P (now));
879 return 0;
880 #endif /* not TARGET_API_MAC_CARBON */
884 /* Called in sys_select to wait for an alarm signal to arrive. */
887 pause ()
889 EventRecord e;
890 unsigned long tick;
892 if (!target_ticks) /* no alarm pending */
893 return -1;
895 if ((tick = TickCount ()) < target_ticks)
896 WaitNextEvent (0, &e, target_ticks - tick, NULL); /* Accept no event;
897 just wait. by T.I. */
899 target_ticks = 0;
900 if (alarm_signal_func)
901 (*alarm_signal_func)(SIGALRM);
903 return 0;
908 alarm (int seconds)
910 long remaining = target_ticks ? (TickCount () - target_ticks) / 60 : 0;
912 target_ticks = seconds ? TickCount () + 60 * seconds : 0;
914 return (remaining < 0) ? 0 : (unsigned int) remaining;
918 #undef signal
919 #ifdef __MRC__
920 extern __sigfun signal (int signal, __sigfun signal_func);
921 __sigfun
922 sys_signal (int signal_num, __sigfun signal_func)
923 #elif __MWERKS__
924 extern __signal_func_ptr signal (int signal, __signal_func_ptr signal_func);
925 __signal_func_ptr
926 sys_signal (int signal_num, __signal_func_ptr signal_func)
927 #else /* not __MRC__ and not __MWERKS__ */
928 You lose!!!
929 #endif /* not __MRC__ and not __MWERKS__ */
931 if (signal_num != SIGALRM)
932 return signal (signal_num, signal_func);
933 else
935 #ifdef __MRC__
936 __sigfun old_signal_func;
937 #elif __MWERKS__
938 __signal_func_ptr old_signal_func;
939 #else
940 You lose!!!
941 #endif
942 old_signal_func = alarm_signal_func;
943 alarm_signal_func = signal_func;
944 return old_signal_func;
949 /* gettimeofday should return the amount of time (in a timeval
950 structure) since midnight today. The toolbox function Microseconds
951 returns the number of microseconds (in a UnsignedWide value) since
952 the machine was booted. Also making this complicated is WideAdd,
953 WideSubtract, etc. take wide values. */
956 gettimeofday (tp)
957 struct timeval *tp;
959 static inited = 0;
960 static wide wall_clock_at_epoch, clicks_at_epoch;
961 UnsignedWide uw_microseconds;
962 wide w_microseconds;
963 time_t sys_time (time_t *);
965 /* If this function is called for the first time, record the number
966 of seconds since midnight and the number of microseconds since
967 boot at the time of this first call. */
968 if (!inited)
970 time_t systime;
971 inited = 1;
972 systime = sys_time (NULL);
973 /* Store microseconds since midnight in wall_clock_at_epoch. */
974 WideMultiply (systime, 1000000L, &wall_clock_at_epoch);
975 Microseconds (&uw_microseconds);
976 /* Store microseconds since boot in clicks_at_epoch. */
977 clicks_at_epoch.hi = uw_microseconds.hi;
978 clicks_at_epoch.lo = uw_microseconds.lo;
981 /* Get time since boot */
982 Microseconds (&uw_microseconds);
984 /* Convert to time since midnight*/
985 w_microseconds.hi = uw_microseconds.hi;
986 w_microseconds.lo = uw_microseconds.lo;
987 WideSubtract (&w_microseconds, &clicks_at_epoch);
988 WideAdd (&w_microseconds, &wall_clock_at_epoch);
989 tp->tv_sec = WideDivide (&w_microseconds, 1000000L, &tp->tv_usec);
991 return 0;
995 #ifdef __MRC__
996 unsigned int
997 sleep (unsigned int seconds)
999 unsigned long time_up;
1000 EventRecord e;
1002 time_up = TickCount () + seconds * 60;
1003 while (TickCount () < time_up)
1005 /* Accept no event; just wait. by T.I. */
1006 WaitNextEvent (0, &e, 30, NULL);
1009 return (0);
1011 #endif /* __MRC__ */
1014 /* The time functions adjust time values according to the difference
1015 between the Unix and CW epoches. */
1017 #undef gmtime
1018 extern struct tm *gmtime (const time_t *);
1019 struct tm *
1020 sys_gmtime (const time_t *timer)
1022 time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
1024 return gmtime (&unix_time);
1028 #undef localtime
1029 extern struct tm *localtime (const time_t *);
1030 struct tm *
1031 sys_localtime (const time_t *timer)
1033 #if __MSL__ >= 0x6000
1034 time_t unix_time = *timer;
1035 #else
1036 time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
1037 #endif
1039 return localtime (&unix_time);
1043 #undef ctime
1044 extern char *ctime (const time_t *);
1045 char *
1046 sys_ctime (const time_t *timer)
1048 #if __MSL__ >= 0x6000
1049 time_t unix_time = *timer;
1050 #else
1051 time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
1052 #endif
1054 return ctime (&unix_time);
1058 #undef time
1059 extern time_t time (time_t *);
1060 time_t
1061 sys_time (time_t *timer)
1063 #if __MSL__ >= 0x6000
1064 time_t mac_time = time (NULL);
1065 #else
1066 time_t mac_time = time (NULL) - CW_OR_MPW_UNIX_EPOCH_DIFF;
1067 #endif
1069 if (timer)
1070 *timer = mac_time;
1072 return mac_time;
1076 /* MPW strftime broken for "%p" format */
1077 #ifdef __MRC__
1078 #undef strftime
1079 #include <time.h>
1080 size_t
1081 sys_strftime (char * s, size_t maxsize, const char * format,
1082 const struct tm * timeptr)
1084 if (strcmp (format, "%p") == 0)
1086 if (maxsize < 3)
1087 return 0;
1088 if (timeptr->tm_hour < 12)
1090 strcpy (s, "AM");
1091 return 2;
1093 else
1095 strcpy (s, "PM");
1096 return 2;
1099 else
1100 return strftime (s, maxsize, format, timeptr);
1102 #endif /* __MRC__ */
1105 /* no subprocesses, empty wait */
1108 wait (int pid)
1110 return 0;
1114 void
1115 croak (char *badfunc)
1117 printf ("%s not yet implemented\r\n", badfunc);
1118 exit (1);
1122 char *
1123 index (const char * str, int chr)
1125 return strchr (str, chr);
1129 char *
1130 mktemp (char *template)
1132 int len, k;
1133 static seqnum = 0;
1135 len = strlen (template);
1136 k = len - 1;
1137 while (k >= 0 && template[k] == 'X')
1138 k--;
1140 k++; /* make k index of first 'X' */
1142 if (k < len)
1144 /* Zero filled, number of digits equal to the number of X's. */
1145 sprintf (&template[k], "%0*d", len-k, seqnum++);
1147 return template;
1149 else
1150 return 0;
1154 /* Emulate getpwuid, getpwnam and others. */
1156 #define PASSWD_FIELD_SIZE 256
1158 static char my_passwd_name[PASSWD_FIELD_SIZE];
1159 static char my_passwd_dir[MAXPATHLEN+1];
1161 static struct passwd my_passwd =
1163 my_passwd_name,
1164 my_passwd_dir,
1168 /* Initialized by main () in macterm.c to pathname of emacs directory. */
1170 char emacs_passwd_dir[MAXPATHLEN+1];
1172 char *
1173 getwd (char *);
1175 void
1176 init_emacs_passwd_dir ()
1178 int found = false;
1180 if (getwd (emacs_passwd_dir) && getwd (my_passwd_dir))
1182 /* Need pathname of first ancestor that begins with "emacs"
1183 since Mac emacs application is somewhere in the emacs-*
1184 tree. */
1185 int len = strlen (emacs_passwd_dir);
1186 int j = len - 1;
1187 /* j points to the "/" following the directory name being
1188 compared. */
1189 int i = j - 1;
1190 while (i >= 0 && !found)
1192 while (i >= 0 && emacs_passwd_dir[i] != '/')
1193 i--;
1194 if (emacs_passwd_dir[i] == '/' && i+5 < len)
1195 found = (strncmp (&(emacs_passwd_dir[i+1]), "emacs", 5) == 0);
1196 if (found)
1197 emacs_passwd_dir[j+1] = '\0';
1198 else
1200 j = i;
1201 i = j - 1;
1206 if (!found)
1208 /* Setting to "/" probably won't work but set it to something
1209 anyway. */
1210 strcpy (emacs_passwd_dir, "/");
1211 strcpy (my_passwd_dir, "/");
1216 static struct passwd emacs_passwd =
1218 "emacs",
1219 emacs_passwd_dir,
1222 static int my_passwd_inited = 0;
1225 static void
1226 init_my_passwd ()
1228 char **owner_name;
1230 /* Note: my_passwd_dir initialized in int_emacs_passwd_dir to
1231 directory where Emacs was started. */
1233 owner_name = (char **) GetResource ('STR ',-16096);
1234 if (owner_name)
1236 HLock (owner_name);
1237 BlockMove ((unsigned char *) *owner_name,
1238 (unsigned char *) my_passwd_name,
1239 *owner_name[0]+1);
1240 HUnlock (owner_name);
1241 p2cstr ((unsigned char *) my_passwd_name);
1243 else
1244 my_passwd_name[0] = 0;
1248 struct passwd *
1249 getpwuid (uid_t uid)
1251 if (!my_passwd_inited)
1253 init_my_passwd ();
1254 my_passwd_inited = 1;
1257 return &my_passwd;
1261 struct passwd *
1262 getpwnam (const char *name)
1264 if (strcmp (name, "emacs") == 0)
1265 return &emacs_passwd;
1267 if (!my_passwd_inited)
1269 init_my_passwd ();
1270 my_passwd_inited = 1;
1273 return &my_passwd;
1277 /* The functions fork, kill, sigsetmask, sigblock, request_sigio,
1278 setpgrp, setpriority, and unrequest_sigio are defined to be empty
1279 as in msdos.c. */
1283 fork ()
1285 return -1;
1290 kill (int x, int y)
1292 return -1;
1296 void
1297 sys_subshell ()
1299 error ("Can't spawn subshell");
1304 sigsetmask (int x)
1306 return 0;
1311 sigblock (int mask)
1313 return 0;
1317 void
1318 request_sigio (void)
1323 void
1324 unrequest_sigio (void)
1330 setpgrp ()
1332 return 0;
1336 /* No pipes yet. */
1339 pipe (int _fildes[2])
1341 errno = EACCES;
1342 return -1;
1346 /* Hard and symbolic links. */
1349 symlink (const char *name1, const char *name2)
1351 errno = ENOENT;
1352 return -1;
1357 link (const char *name1, const char *name2)
1359 errno = ENOENT;
1360 return -1;
1363 #endif /* ! MAC_OSX */
1365 /* Determine the path name of the file specified by VREFNUM, DIRID,
1366 and NAME and place that in the buffer PATH of length
1367 MAXPATHLEN. */
1369 path_from_vol_dir_name (char *path, int man_path_len, short vol_ref_num,
1370 long dir_id, ConstStr255Param name)
1372 Str255 dir_name;
1373 CInfoPBRec cipb;
1374 OSErr err;
1376 if (strlen (name) > man_path_len)
1377 return 0;
1379 memcpy (dir_name, name, name[0]+1);
1380 memcpy (path, name, name[0]+1);
1381 p2cstr (path);
1383 cipb.dirInfo.ioDrParID = dir_id;
1384 cipb.dirInfo.ioNamePtr = dir_name;
1388 cipb.dirInfo.ioVRefNum = vol_ref_num;
1389 cipb.dirInfo.ioFDirIndex = -1;
1390 cipb.dirInfo.ioDrDirID = cipb.dirInfo.ioDrParID;
1391 /* go up to parent each time */
1393 err = PBGetCatInfo (&cipb, false);
1394 if (err != noErr)
1395 return 0;
1397 p2cstr (dir_name);
1398 if (strlen (dir_name) + strlen (path) + 1 >= man_path_len)
1399 return 0;
1401 strcat (dir_name, ":");
1402 strcat (dir_name, path);
1403 /* attach to front since we're going up directory tree */
1404 strcpy (path, dir_name);
1406 while (cipb.dirInfo.ioDrDirID != fsRtDirID);
1407 /* stop when we see the volume's root directory */
1409 return 1; /* success */
1412 #ifndef MAC_OSX
1415 readlink (const char *path, char *buf, int bufsiz)
1417 char mac_sym_link_name[MAXPATHLEN+1];
1418 OSErr err;
1419 FSSpec fsspec;
1420 Boolean target_is_folder, was_aliased;
1421 Str255 directory_name, mac_pathname;
1422 CInfoPBRec cipb;
1424 if (posix_to_mac_pathname (path, mac_sym_link_name, MAXPATHLEN+1) == 0)
1425 return -1;
1427 c2pstr (mac_sym_link_name);
1428 err = FSMakeFSSpec (0, 0, mac_sym_link_name, &fsspec);
1429 if (err != noErr)
1431 errno = ENOENT;
1432 return -1;
1435 err = ResolveAliasFile (&fsspec, true, &target_is_folder, &was_aliased);
1436 if (err != noErr || !was_aliased)
1438 errno = ENOENT;
1439 return -1;
1442 if (path_from_vol_dir_name (mac_pathname, 255, fsspec.vRefNum, fsspec.parID,
1443 fsspec.name) == 0)
1445 errno = ENOENT;
1446 return -1;
1449 if (mac_to_posix_pathname (mac_pathname, buf, bufsiz) == 0)
1451 errno = ENOENT;
1452 return -1;
1455 return strlen (buf);
1459 /* Convert a path to one with aliases fully expanded. */
1461 static int
1462 find_true_pathname (const char *path, char *buf, int bufsiz)
1464 char *q, temp[MAXPATHLEN+1];
1465 const char *p;
1466 int len;
1468 if (bufsiz <= 0 || path == 0 || path[0] == '\0')
1469 return -1;
1471 buf[0] = '\0';
1473 p = path;
1474 if (*p == '/')
1475 q = strchr (p + 1, '/');
1476 else
1477 q = strchr (p, '/');
1478 len = 0; /* loop may not be entered, e.g., for "/" */
1480 while (q)
1482 strcpy (temp, buf);
1483 strncat (temp, p, q - p);
1484 len = readlink (temp, buf, bufsiz);
1485 if (len <= -1)
1487 if (strlen (temp) + 1 > bufsiz)
1488 return -1;
1489 strcpy (buf, temp);
1491 strcat (buf, "/");
1492 len++;
1493 p = q + 1;
1494 q = strchr(p, '/');
1497 if (len + strlen (p) + 1 >= bufsiz)
1498 return -1;
1500 strcat (buf, p);
1501 return len + strlen (p);
1505 mode_t
1506 umask (mode_t numask)
1508 static mode_t mask = 022;
1509 mode_t oldmask = mask;
1510 mask = numask;
1511 return oldmask;
1516 chmod (const char *path, mode_t mode)
1518 /* say it always succeed for now */
1519 return 0;
1524 dup (int oldd)
1526 #ifdef __MRC__
1527 return fcntl (oldd, F_DUPFD, 0);
1528 #elif __MWERKS__
1529 /* current implementation of fcntl in fcntl.mac.c simply returns old
1530 descriptor */
1531 return fcntl (oldd, F_DUPFD);
1532 #else
1533 You lose!!!
1534 #endif
1538 /* This is from the original sysdep.c. Emulate BSD dup2. First close
1539 newd if it already exists. Then, attempt to dup oldd. If not
1540 successful, call dup2 recursively until we are, then close the
1541 unsuccessful ones. */
1544 dup2 (int oldd, int newd)
1546 int fd, ret;
1548 close (newd);
1550 fd = dup (oldd);
1551 if (fd == -1)
1552 return -1;
1553 if (fd == newd)
1554 return newd;
1555 ret = dup2 (oldd, newd);
1556 close (fd);
1557 return ret;
1561 /* let it fail for now */
1563 char *
1564 sbrk (int incr)
1566 return (char *) -1;
1571 fsync (int fd)
1573 return 0;
1578 ioctl (int d, int request, void *argp)
1580 return -1;
1584 #ifdef __MRC__
1586 isatty (int fildes)
1588 if (fildes >=0 && fildes <= 2)
1589 return 1;
1590 else
1591 return 0;
1596 getgid ()
1598 return 100;
1603 getegid ()
1605 return 100;
1610 getuid ()
1612 return 200;
1617 geteuid ()
1619 return 200;
1621 #endif /* __MRC__ */
1624 #ifdef __MWERKS__
1625 #if __MSL__ < 0x6000
1626 #undef getpid
1628 getpid ()
1630 return 9999;
1632 #endif
1633 #endif /* __MWERKS__ */
1635 #endif /* ! MAC_OSX */
1638 /* Return the path to the directory in which Emacs can create
1639 temporary files. The MacOS "temporary items" directory cannot be
1640 used because it removes the file written by a process when it
1641 exits. In that sense it's more like "/dev/null" than "/tmp" (but
1642 again not exactly). And of course Emacs needs to read back the
1643 files written by its subprocesses. So here we write the files to a
1644 directory "Emacs" in the Preferences Folder. This directory is
1645 created if it does not exist. */
1647 char *
1648 get_temp_dir_name ()
1650 static char *temp_dir_name = NULL;
1651 short vol_ref_num;
1652 long dir_id;
1653 OSErr err;
1654 Str255 dir_name, full_path;
1655 CInfoPBRec cpb;
1656 char unix_dir_name[MAXPATHLEN+1];
1657 DIR *dir;
1659 /* Cache directory name with pointer temp_dir_name.
1660 Look for it only the first time. */
1661 if (!temp_dir_name)
1663 err = FindFolder (kOnSystemDisk, kPreferencesFolderType, kCreateFolder,
1664 &vol_ref_num, &dir_id);
1665 if (err != noErr)
1666 return NULL;
1668 if (!path_from_vol_dir_name (full_path, 255, vol_ref_num, dir_id, "\p"))
1669 return NULL;
1671 if (strlen (full_path) + 6 <= MAXPATHLEN)
1672 strcat (full_path, "Emacs:");
1673 else
1674 return NULL;
1676 if (!mac_to_posix_pathname (full_path, unix_dir_name, MAXPATHLEN+1))
1677 return NULL;
1679 dir = opendir (unix_dir_name); /* check whether temp directory exists */
1680 if (dir)
1681 closedir (dir);
1682 else if (mkdir (unix_dir_name, 0700) != 0) /* create it if not */
1683 return NULL;
1685 temp_dir_name = (char *) malloc (strlen (unix_dir_name) + 1);
1686 strcpy (temp_dir_name, unix_dir_name);
1689 return temp_dir_name;
1692 #ifndef MAC_OSX
1694 /* Allocate and construct an array of pointers to strings from a list
1695 of strings stored in a 'STR#' resource. The returned pointer array
1696 is stored in the style of argv and environ: if the 'STR#' resource
1697 contains numString strings, a pointer array with numString+1
1698 elements is returned in which the last entry contains a null
1699 pointer. The pointer to the pointer array is passed by pointer in
1700 parameter t. The resource ID of the 'STR#' resource is passed in
1701 parameter StringListID.
1704 void
1705 get_string_list (char ***t, short string_list_id)
1707 Handle h;
1708 Ptr p;
1709 int i, num_strings;
1711 h = GetResource ('STR#', string_list_id);
1712 if (h)
1714 HLock (h);
1715 p = *h;
1716 num_strings = * (short *) p;
1717 p += sizeof(short);
1718 *t = (char **) malloc (sizeof (char *) * (num_strings + 1));
1719 for (i = 0; i < num_strings; i++)
1721 short length = *p++;
1722 (*t)[i] = (char *) malloc (length + 1);
1723 strncpy ((*t)[i], p, length);
1724 (*t)[i][length] = '\0';
1725 p += length;
1727 (*t)[num_strings] = 0;
1728 HUnlock (h);
1730 else
1732 /* Return no string in case GetResource fails. Bug fixed by
1733 Ikegami Tsutomu. Caused MPW build to crash without sym -on
1734 option (no sym -on implies -opt local). */
1735 *t = (char **) malloc (sizeof (char *));
1736 (*t)[0] = 0;
1741 static char *
1742 get_path_to_system_folder ()
1744 short vol_ref_num;
1745 long dir_id;
1746 OSErr err;
1747 Str255 dir_name, full_path;
1748 CInfoPBRec cpb;
1749 static char system_folder_unix_name[MAXPATHLEN+1];
1750 DIR *dir;
1752 err = FindFolder (kOnSystemDisk, kSystemFolderType, kDontCreateFolder,
1753 &vol_ref_num, &dir_id);
1754 if (err != noErr)
1755 return NULL;
1757 if (!path_from_vol_dir_name (full_path, 255, vol_ref_num, dir_id, "\p"))
1758 return NULL;
1760 if (!mac_to_posix_pathname (full_path, system_folder_unix_name,
1761 MAXPATHLEN+1))
1762 return NULL;
1764 return system_folder_unix_name;
1768 char **environ;
1770 #define ENVIRON_STRING_LIST_ID 128
1772 /* Get environment variable definitions from STR# resource. */
1774 void
1775 init_environ ()
1777 int i;
1779 get_string_list (&environ, ENVIRON_STRING_LIST_ID);
1781 i = 0;
1782 while (environ[i])
1783 i++;
1785 /* Make HOME directory the one Emacs starts up in if not specified
1786 by resource. */
1787 if (getenv ("HOME") == NULL)
1789 environ = (char **) realloc (environ, sizeof (char *) * (i + 2));
1790 if (environ)
1792 environ[i] = (char *) malloc (strlen (my_passwd_dir) + 6);
1793 if (environ[i])
1795 strcpy (environ[i], "HOME=");
1796 strcat (environ[i], my_passwd_dir);
1798 environ[i+1] = 0;
1799 i++;
1803 /* Make HOME directory the one Emacs starts up in if not specified
1804 by resource. */
1805 if (getenv ("MAIL") == NULL)
1807 environ = (char **) realloc (environ, sizeof (char *) * (i + 2));
1808 if (environ)
1810 char * path_to_system_folder = get_path_to_system_folder ();
1811 environ[i] = (char *) malloc (strlen (path_to_system_folder) + 22);
1812 if (environ[i])
1814 strcpy (environ[i], "MAIL=");
1815 strcat (environ[i], path_to_system_folder);
1816 strcat (environ[i], "Eudora Folder/In");
1818 environ[i+1] = 0;
1824 /* Return the value of the environment variable NAME. */
1826 char *
1827 getenv (const char *name)
1829 int length = strlen(name);
1830 char **e;
1832 for (e = environ; *e != 0; e++)
1833 if (strncmp(*e, name, length) == 0 && (*e)[length] == '=')
1834 return &(*e)[length + 1];
1836 if (strcmp (name, "TMPDIR") == 0)
1837 return get_temp_dir_name ();
1839 return 0;
1843 #ifdef __MRC__
1844 /* see Interfaces&Libraries:Interfaces:CIncludes:signal.h */
1845 char *sys_siglist[] =
1847 "Zero is not a signal!!!",
1848 "Abort", /* 1 */
1849 "Interactive user interrupt", /* 2 */ "?",
1850 "Floating point exception", /* 4 */ "?", "?", "?",
1851 "Illegal instruction", /* 8 */ "?", "?", "?", "?", "?", "?", "?",
1852 "Segment violation", /* 16 */ "?", "?", "?", "?", "?", "?", "?",
1853 "?", "?", "?", "?", "?", "?", "?", "?",
1854 "Terminal" /* 32 */
1856 #elif __MWERKS__
1857 char *sys_siglist[] =
1859 "Zero is not a signal!!!",
1860 "Abort",
1861 "Floating point exception",
1862 "Illegal instruction",
1863 "Interactive user interrupt",
1864 "Segment violation",
1865 "Terminal"
1867 #else /* not __MRC__ and not __MWERKS__ */
1868 You lose!!!
1869 #endif /* not __MRC__ and not __MWERKS__ */
1872 #include <utsname.h>
1875 uname (struct utsname *name)
1877 char **system_name;
1878 system_name = GetString (-16413); /* IM - Resource Manager Reference */
1879 if (system_name)
1881 BlockMove (*system_name, name->nodename, (*system_name)[0]+1);
1882 p2cstr (name->nodename);
1883 return 0;
1885 else
1886 return -1;
1890 #include <Processes.h>
1891 #include <EPPC.h>
1893 /* Event class of HLE sent to subprocess. */
1894 const OSType kEmacsSubprocessSend = 'ESND';
1896 /* Event class of HLE sent back from subprocess. */
1897 const OSType kEmacsSubprocessReply = 'ERPY';
1900 char *
1901 mystrchr (char *s, char c)
1903 while (*s && *s != c)
1905 if (*s == '\\')
1906 s++;
1907 s++;
1910 if (*s)
1912 *s = '\0';
1913 return s;
1915 else
1916 return NULL;
1920 char *
1921 mystrtok (char *s)
1923 while (*s)
1924 s++;
1926 return s + 1;
1930 void
1931 mystrcpy (char *to, char *from)
1933 while (*from)
1935 if (*from == '\\')
1936 from++;
1937 *to++ = *from++;
1939 *to = '\0';
1943 /* Start a Mac subprocess. Arguments for it is passed in argv (null
1944 terminated). The process should run with the default directory
1945 "workdir", read input from "infn", and write output and error to
1946 "outfn" and "errfn", resp. The Process Manager call
1947 LaunchApplication is used to start the subprocess. We use high
1948 level events as the mechanism to pass arguments to the subprocess
1949 and to make Emacs wait for the subprocess to terminate and pass
1950 back a result code. The bulk of the code here packs the arguments
1951 into one message to be passed together with the high level event.
1952 Emacs also sometimes starts a subprocess using a shell to perform
1953 wildcard filename expansion. Since we don't really have a shell on
1954 the Mac, this case is detected and the starting of the shell is
1955 by-passed. We really need to add code here to do filename
1956 expansion to support such functionality. */
1959 run_mac_command (argv, workdir, infn, outfn, errfn)
1960 unsigned char **argv;
1961 const char *workdir;
1962 const char *infn, *outfn, *errfn;
1964 #ifdef TARGET_API_MAC_CARBON
1965 return -1;
1966 #else /* not TARGET_API_MAC_CARBON */
1967 char macappname[MAXPATHLEN+1], macworkdir[MAXPATHLEN+1];
1968 char macinfn[MAXPATHLEN+1], macoutfn[MAXPATHLEN+1], macerrfn[MAXPATHLEN+1];
1969 int paramlen, argc, newargc, j, retries;
1970 char **newargv, *param, *p;
1971 OSErr iErr;
1972 FSSpec spec;
1973 LaunchParamBlockRec lpbr;
1974 EventRecord send_event, reply_event;
1975 RgnHandle cursor_region_handle;
1976 TargetID targ;
1977 unsigned long ref_con, len;
1979 if (posix_to_mac_pathname (workdir, macworkdir, MAXPATHLEN+1) == 0)
1980 return -1;
1981 if (posix_to_mac_pathname (infn, macinfn, MAXPATHLEN+1) == 0)
1982 return -1;
1983 if (posix_to_mac_pathname (outfn, macoutfn, MAXPATHLEN+1) == 0)
1984 return -1;
1985 if (posix_to_mac_pathname (errfn, macerrfn, MAXPATHLEN+1) == 0)
1986 return -1;
1988 paramlen = strlen (macworkdir) + strlen (macinfn) + strlen (macoutfn)
1989 + strlen (macerrfn) + 4; /* count nulls at end of strings */
1991 argc = 0;
1992 while (argv[argc])
1993 argc++;
1995 if (argc == 0)
1996 return -1;
1998 /* If a subprocess is invoked with a shell, we receive 3 arguments
1999 of the form: "<path to emacs bins>/sh" "-c" "<path to emacs
2000 bins>/<command> <command args>" */
2001 j = strlen (argv[0]);
2002 if (j >= 3 && strcmp (argv[0]+j-3, "/sh") == 0
2003 && argc == 3 && strcmp (argv[1], "-c") == 0)
2005 char *command, *t, tempmacpathname[MAXPATHLEN+1];
2007 /* The arguments for the command in argv[2] are separated by
2008 spaces. Count them and put the count in newargc. */
2009 command = (char *) alloca (strlen (argv[2])+2);
2010 strcpy (command, argv[2]);
2011 if (command[strlen (command) - 1] != ' ')
2012 strcat (command, " ");
2014 t = command;
2015 newargc = 0;
2016 t = mystrchr (t, ' ');
2017 while (t)
2019 newargc++;
2020 t = mystrchr (t+1, ' ');
2023 newargv = (char **) alloca (sizeof (char *) * newargc);
2025 t = command;
2026 for (j = 0; j < newargc; j++)
2028 newargv[j] = (char *) alloca (strlen (t) + 1);
2029 mystrcpy (newargv[j], t);
2031 t = mystrtok (t);
2032 paramlen += strlen (newargv[j]) + 1;
2035 if (strncmp (newargv[0], "~emacs/", 7) == 0)
2037 if (posix_to_mac_pathname (newargv[0], tempmacpathname, MAXPATHLEN+1)
2038 == 0)
2039 return -1;
2041 else
2042 { /* sometimes Emacs call "sh" without a path for the command */
2043 #if 0
2044 char *t = (char *) alloca (strlen (newargv[0]) + 7 + 1);
2045 strcpy (t, "~emacs/");
2046 strcat (t, newargv[0]);
2047 #endif /* 0 */
2048 Lisp_Object path;
2049 openp (Vexec_path, build_string (newargv[0]), EXEC_SUFFIXES, &path,
2050 make_number (X_OK));
2052 if (NILP (path))
2053 return -1;
2054 if (posix_to_mac_pathname (SDATA (path), tempmacpathname,
2055 MAXPATHLEN+1) == 0)
2056 return -1;
2058 strcpy (macappname, tempmacpathname);
2060 else
2062 if (posix_to_mac_pathname (argv[0], macappname, MAXPATHLEN+1) == 0)
2063 return -1;
2065 newargv = (char **) alloca (sizeof (char *) * argc);
2066 newargc = argc;
2067 for (j = 1; j < argc; j++)
2069 if (strncmp (argv[j], "~emacs/", 7) == 0)
2071 char *t = strchr (argv[j], ' ');
2072 if (t)
2074 char tempcmdname[MAXPATHLEN+1], tempmaccmdname[MAXPATHLEN+1];
2075 strncpy (tempcmdname, argv[j], t-argv[j]);
2076 tempcmdname[t-argv[j]] = '\0';
2077 if (posix_to_mac_pathname (tempcmdname, tempmaccmdname,
2078 MAXPATHLEN+1) == 0)
2079 return -1;
2080 newargv[j] = (char *) alloca (strlen (tempmaccmdname)
2081 + strlen (t) + 1);
2082 strcpy (newargv[j], tempmaccmdname);
2083 strcat (newargv[j], t);
2085 else
2087 char tempmaccmdname[MAXPATHLEN+1];
2088 if (posix_to_mac_pathname (argv[j], tempmaccmdname,
2089 MAXPATHLEN+1) == 0)
2090 return -1;
2091 newargv[j] = (char *) alloca (strlen (tempmaccmdname)+1);
2092 strcpy (newargv[j], tempmaccmdname);
2095 else
2096 newargv[j] = argv[j];
2097 paramlen += strlen (newargv[j]) + 1;
2101 /* After expanding all the arguments, we now know the length of the
2102 parameter block to be sent to the subprocess as a message
2103 attached to the HLE. */
2104 param = (char *) malloc (paramlen + 1);
2105 if (!param)
2106 return -1;
2108 p = param;
2109 *p++ = newargc;
2110 /* first byte of message contains number of arguments for command */
2111 strcpy (p, macworkdir);
2112 p += strlen (macworkdir);
2113 *p++ = '\0';
2114 /* null terminate strings sent so it's possible to use strcpy over there */
2115 strcpy (p, macinfn);
2116 p += strlen (macinfn);
2117 *p++ = '\0';
2118 strcpy (p, macoutfn);
2119 p += strlen (macoutfn);
2120 *p++ = '\0';
2121 strcpy (p, macerrfn);
2122 p += strlen (macerrfn);
2123 *p++ = '\0';
2124 for (j = 1; j < newargc; j++)
2126 strcpy (p, newargv[j]);
2127 p += strlen (newargv[j]);
2128 *p++ = '\0';
2131 c2pstr (macappname);
2133 iErr = FSMakeFSSpec (0, 0, macappname, &spec);
2135 if (iErr != noErr)
2137 free (param);
2138 return -1;
2141 lpbr.launchBlockID = extendedBlock;
2142 lpbr.launchEPBLength = extendedBlockLen;
2143 lpbr.launchControlFlags = launchContinue + launchNoFileFlags;
2144 lpbr.launchAppSpec = &spec;
2145 lpbr.launchAppParameters = NULL;
2147 iErr = LaunchApplication (&lpbr); /* call the subprocess */
2148 if (iErr != noErr)
2150 free (param);
2151 return -1;
2154 send_event.what = kHighLevelEvent;
2155 send_event.message = kEmacsSubprocessSend;
2156 /* Event ID stored in "where" unused */
2158 retries = 3;
2159 /* OS may think current subprocess has terminated if previous one
2160 terminated recently. */
2163 iErr = PostHighLevelEvent (&send_event, &lpbr.launchProcessSN, 0, param,
2164 paramlen + 1, receiverIDisPSN);
2166 while (iErr == sessClosedErr && retries-- > 0);
2168 if (iErr != noErr)
2170 free (param);
2171 return -1;
2174 cursor_region_handle = NewRgn ();
2176 /* Wait for the subprocess to finish, when it will send us a ERPY
2177 high level event. */
2178 while (1)
2179 if (WaitNextEvent (highLevelEventMask, &reply_event, 180,
2180 cursor_region_handle)
2181 && reply_event.message == kEmacsSubprocessReply)
2182 break;
2184 /* The return code is sent through the refCon */
2185 iErr = AcceptHighLevelEvent (&targ, &ref_con, NULL, &len);
2186 if (iErr != noErr)
2188 DisposeHandle ((Handle) cursor_region_handle);
2189 free (param);
2190 return -1;
2193 DisposeHandle ((Handle) cursor_region_handle);
2194 free (param);
2196 return ref_con;
2197 #endif /* not TARGET_API_MAC_CARBON */
2201 DIR *
2202 opendir (const char *dirname)
2204 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
2205 char mac_pathname[MAXPATHLEN+1], vol_name[MAXPATHLEN+1];
2206 DIR *dirp;
2207 CInfoPBRec cipb;
2208 HVolumeParam vpb;
2209 int len, vol_name_len;
2211 if (find_true_pathname (dirname, true_pathname, MAXPATHLEN+1) == -1)
2212 return 0;
2214 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
2215 if (len > -1)
2216 fully_resolved_name[len] = '\0';
2217 else
2218 strcpy (fully_resolved_name, true_pathname);
2220 dirp = (DIR *) malloc (sizeof(DIR));
2221 if (!dirp)
2222 return 0;
2224 /* Handle special case when dirname is "/": sets up for readir to
2225 get all mount volumes. */
2226 if (strcmp (fully_resolved_name, "/") == 0)
2228 dirp->getting_volumes = 1; /* special all mounted volumes DIR struct */
2229 dirp->current_index = 1; /* index for first volume */
2230 return dirp;
2233 /* Handle typical cases: not accessing all mounted volumes. */
2234 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
2235 return 0;
2237 /* Emacs calls opendir without the trailing '/', Mac needs trailing ':' */
2238 len = strlen (mac_pathname);
2239 if (mac_pathname[len - 1] != ':' && len < MAXPATHLEN)
2240 strcat (mac_pathname, ":");
2242 /* Extract volume name */
2243 vol_name_len = strchr (mac_pathname, ':') - mac_pathname;
2244 strncpy (vol_name, mac_pathname, vol_name_len);
2245 vol_name[vol_name_len] = '\0';
2246 strcat (vol_name, ":");
2248 c2pstr (mac_pathname);
2249 cipb.hFileInfo.ioNamePtr = mac_pathname;
2250 /* using full pathname so vRefNum and DirID ignored */
2251 cipb.hFileInfo.ioVRefNum = 0;
2252 cipb.hFileInfo.ioDirID = 0;
2253 cipb.hFileInfo.ioFDirIndex = 0;
2254 /* set to 0 to get information about specific dir or file */
2256 errno = PBGetCatInfo (&cipb, false);
2257 if (errno != noErr)
2259 errno = ENOENT;
2260 return 0;
2263 if (!(cipb.hFileInfo.ioFlAttrib & 0x10)) /* bit 4 = 1 for directories */
2264 return 0; /* not a directory */
2266 dirp->dir_id = cipb.dirInfo.ioDrDirID; /* used later in readdir */
2267 dirp->getting_volumes = 0;
2268 dirp->current_index = 1; /* index for first file/directory */
2270 c2pstr (vol_name);
2271 vpb.ioNamePtr = vol_name;
2272 /* using full pathname so vRefNum and DirID ignored */
2273 vpb.ioVRefNum = 0;
2274 vpb.ioVolIndex = -1;
2275 errno = PBHGetVInfo ((union HParamBlockRec *) &vpb, false);
2276 if (errno != noErr)
2278 errno = ENOENT;
2279 return 0;
2282 dirp->vol_ref_num = vpb.ioVRefNum;
2284 return dirp;
2288 closedir (DIR *dp)
2290 free (dp);
2292 return 0;
2296 struct dirent *
2297 readdir (DIR *dp)
2299 HParamBlockRec hpblock;
2300 CInfoPBRec cipb;
2301 static struct dirent s_dirent;
2302 static Str255 s_name;
2303 int done;
2304 char *p;
2306 /* Handle the root directory containing the mounted volumes. Call
2307 PBHGetVInfo specifying an index to obtain the info for a volume.
2308 PBHGetVInfo returns an error when it receives an index beyond the
2309 last volume, at which time we should return a nil dirent struct
2310 pointer. */
2311 if (dp->getting_volumes)
2313 hpblock.volumeParam.ioNamePtr = s_name;
2314 hpblock.volumeParam.ioVRefNum = 0;
2315 hpblock.volumeParam.ioVolIndex = dp->current_index;
2317 errno = PBHGetVInfo (&hpblock, false);
2318 if (errno != noErr)
2320 errno = ENOENT;
2321 return 0;
2324 p2cstr (s_name);
2325 strcat (s_name, "/"); /* need "/" for stat to work correctly */
2327 dp->current_index++;
2329 s_dirent.d_ino = hpblock.volumeParam.ioVRefNum;
2330 s_dirent.d_name = s_name;
2332 return &s_dirent;
2334 else
2336 cipb.hFileInfo.ioVRefNum = dp->vol_ref_num;
2337 cipb.hFileInfo.ioNamePtr = s_name;
2338 /* location to receive filename returned */
2340 /* return only visible files */
2341 done = false;
2342 while (!done)
2344 cipb.hFileInfo.ioDirID = dp->dir_id;
2345 /* directory ID found by opendir */
2346 cipb.hFileInfo.ioFDirIndex = dp->current_index;
2348 errno = PBGetCatInfo (&cipb, false);
2349 if (errno != noErr)
2351 errno = ENOENT;
2352 return 0;
2355 /* insist on a visible entry */
2356 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* directory? */
2357 done = !(cipb.dirInfo.ioDrUsrWds.frFlags & fInvisible);
2358 else
2359 done = !(cipb.hFileInfo.ioFlFndrInfo.fdFlags & fInvisible);
2361 dp->current_index++;
2364 p2cstr (s_name);
2366 p = s_name;
2367 while (*p)
2369 if (*p == '/')
2370 *p = ':';
2371 p++;
2374 s_dirent.d_ino = cipb.dirInfo.ioDrDirID;
2375 /* value unimportant: non-zero for valid file */
2376 s_dirent.d_name = s_name;
2378 return &s_dirent;
2383 char *
2384 getwd (char *path)
2386 char mac_pathname[MAXPATHLEN+1];
2387 Str255 directory_name;
2388 OSErr errno;
2389 CInfoPBRec cipb;
2391 if (path_from_vol_dir_name (mac_pathname, 255, 0, 0, "\p") == 0)
2392 return NULL;
2394 if (mac_to_posix_pathname (mac_pathname, path, MAXPATHLEN+1) == 0)
2395 return 0;
2396 else
2397 return path;
2400 #endif /* ! MAC_OSX */
2403 void
2404 initialize_applescript ()
2406 AEDesc null_desc;
2407 OSAError osaerror;
2409 /* if open fails, as_scripting_component is set to NULL. Its
2410 subsequent use in OSA calls will fail with badComponentInstance
2411 error. */
2412 as_scripting_component = OpenDefaultComponent (kOSAComponentType,
2413 kAppleScriptSubtype);
2415 null_desc.descriptorType = typeNull;
2416 null_desc.dataHandle = 0;
2417 osaerror = OSAMakeContext (as_scripting_component, &null_desc,
2418 kOSANullScript, &as_script_context);
2419 if (osaerror)
2420 as_script_context = kOSANullScript;
2421 /* use default context if create fails */
2425 void terminate_applescript()
2427 OSADispose (as_scripting_component, as_script_context);
2428 CloseComponent (as_scripting_component);
2432 /* Compile and execute the AppleScript SCRIPT and return the error
2433 status as function value. A zero is returned if compilation and
2434 execution is successful, in which case RESULT returns a pointer to
2435 a string containing the resulting script value. Otherwise, the Mac
2436 error code is returned and RESULT returns a pointer to an error
2437 string. In both cases the caller should deallocate the storage
2438 used by the string pointed to by RESULT if it is non-NULL. For
2439 documentation on the MacOS scripting architecture, see Inside
2440 Macintosh - Interapplication Communications: Scripting Components. */
2442 static long
2443 do_applescript (char *script, char **result)
2445 AEDesc script_desc, result_desc, error_desc;
2446 OSErr error;
2447 OSAError osaerror;
2448 long length;
2450 *result = 0;
2452 if (!as_scripting_component)
2453 initialize_applescript();
2455 error = AECreateDesc (typeChar, script, strlen(script), &script_desc);
2456 if (error)
2457 return error;
2459 osaerror = OSADoScript (as_scripting_component, &script_desc, kOSANullScript,
2460 typeChar, kOSAModeNull, &result_desc);
2462 if (osaerror == errOSAScriptError)
2464 /* error executing AppleScript: retrieve error message */
2465 if (!OSAScriptError (as_scripting_component, kOSAErrorMessage, typeChar,
2466 &error_desc))
2468 #if TARGET_API_MAC_CARBON
2469 length = AEGetDescDataSize (&error_desc);
2470 *result = (char *) xmalloc (length + 1);
2471 if (*result)
2473 AEGetDescData (&error_desc, *result, length);
2474 *(*result + length) = '\0';
2476 #else /* not TARGET_API_MAC_CARBON */
2477 HLock (error_desc.dataHandle);
2478 length = GetHandleSize(error_desc.dataHandle);
2479 *result = (char *) xmalloc (length + 1);
2480 if (*result)
2482 memcpy (*result, *(error_desc.dataHandle), length);
2483 *(*result + length) = '\0';
2485 HUnlock (error_desc.dataHandle);
2486 #endif /* not TARGET_API_MAC_CARBON */
2487 AEDisposeDesc (&error_desc);
2490 else if (osaerror == noErr) /* success: retrieve resulting script value */
2492 #if TARGET_API_MAC_CARBON
2493 length = AEGetDescDataSize (&result_desc);
2494 *result = (char *) xmalloc (length + 1);
2495 if (*result)
2497 AEGetDescData (&result_desc, *result, length);
2498 *(*result + length) = '\0';
2500 #else /* not TARGET_API_MAC_CARBON */
2501 HLock (result_desc.dataHandle);
2502 length = GetHandleSize(result_desc.dataHandle);
2503 *result = (char *) xmalloc (length + 1);
2504 if (*result)
2506 memcpy (*result, *(result_desc.dataHandle), length);
2507 *(*result + length) = '\0';
2509 HUnlock (result_desc.dataHandle);
2510 #endif /* not TARGET_API_MAC_CARBON */
2511 AEDisposeDesc (&result_desc);
2514 AEDisposeDesc (&script_desc);
2516 return osaerror;
2520 DEFUN ("do-applescript", Fdo_applescript, Sdo_applescript, 1, 1, 0,
2521 doc: /* Compile and execute AppleScript SCRIPT and retrieve and return the result.
2522 If compilation and execution are successful, the resulting script
2523 value is returned as a string. Otherwise the function aborts and
2524 displays the error message returned by the AppleScript scripting
2525 component. */)
2526 (script)
2527 Lisp_Object script;
2529 char *result, *temp;
2530 Lisp_Object lisp_result;
2531 long status;
2533 CHECK_STRING (script);
2535 status = do_applescript (SDATA (script), &result);
2536 if (status)
2538 if (!result)
2539 error ("AppleScript error %d", status);
2540 else
2542 /* Unfortunately only OSADoScript in do_applescript knows how
2543 how large the resulting script value or error message is
2544 going to be and therefore as caller memory must be
2545 deallocated here. It is necessary to free the error
2546 message before calling error to avoid a memory leak. */
2547 temp = (char *) alloca (strlen (result) + 1);
2548 strcpy (temp, result);
2549 xfree (result);
2550 error (temp);
2553 else
2555 lisp_result = build_string (result);
2556 xfree (result);
2557 return lisp_result;
2562 DEFUN ("mac-file-name-to-posix", Fmac_file_name_to_posix,
2563 Smac_file_name_to_posix, 1, 1, 0,
2564 doc: /* Convert Macintosh filename to Posix form. */)
2565 (mac_filename)
2566 Lisp_Object mac_filename;
2568 char posix_filename[MAXPATHLEN+1];
2570 CHECK_STRING (mac_filename);
2572 if (mac_to_posix_pathname (SDATA (mac_filename), posix_filename,
2573 MAXPATHLEN))
2574 return build_string (posix_filename);
2575 else
2576 return Qnil;
2580 DEFUN ("posix-file-name-to-mac", Fposix_file_name_to_mac,
2581 Sposix_file_name_to_mac, 1, 1, 0,
2582 doc: /* Convert Posix filename to Mac form. */)
2583 (posix_filename)
2584 Lisp_Object posix_filename;
2586 char mac_filename[MAXPATHLEN+1];
2588 CHECK_STRING (posix_filename);
2590 if (posix_to_mac_pathname (SDATA (posix_filename), mac_filename,
2591 MAXPATHLEN))
2592 return build_string (mac_filename);
2593 else
2594 return Qnil;
2598 /* set interprogram-paste-function to mac-paste-function in mac-win.el
2599 to enable Emacs to obtain the contents of the Mac clipboard. */
2600 DEFUN ("mac-paste-function", Fmac_paste_function, Smac_paste_function, 0, 0, 0,
2601 doc: /* Return the contents of the Mac clipboard as a string. */)
2604 #if TARGET_API_MAC_CARBON
2605 ScrapRef scrap;
2606 ScrapFlavorFlags sff;
2607 Size s;
2608 int i;
2609 char *data;
2611 if (GetCurrentScrap (&scrap) != noErr)
2612 return Qnil;
2614 if (GetScrapFlavorFlags (scrap, kScrapFlavorTypeText, &sff) != noErr)
2615 return Qnil;
2617 if (GetScrapFlavorSize (scrap, kScrapFlavorTypeText, &s) != noErr)
2618 return Qnil;
2620 if ((data = (char*) alloca (s)) == NULL)
2621 return Qnil;
2623 if (GetScrapFlavorData (scrap, kScrapFlavorTypeText, &s, data) != noErr
2624 || s == 0)
2625 return Qnil;
2627 /* Emacs expects clipboard contents have Unix-style eol's */
2628 for (i = 0; i < s; i++)
2629 if (data[i] == '\r')
2630 data[i] = '\n';
2632 return make_string (data, s);
2633 #else /* not TARGET_API_MAC_CARBON */
2634 Lisp_Object value;
2635 Handle my_handle;
2636 long scrap_offset, rc, i;
2638 my_handle = NewHandle (0); /* allocate 0-length data area */
2640 rc = GetScrap (my_handle, 'TEXT', &scrap_offset);
2641 if (rc < 0)
2642 return Qnil;
2644 HLock (my_handle);
2646 /* Emacs expects clipboard contents have Unix-style eol's */
2647 for (i = 0; i < rc; i++)
2648 if ((*my_handle)[i] == '\r')
2649 (*my_handle)[i] = '\n';
2651 value = make_string (*my_handle, rc);
2653 HUnlock (my_handle);
2655 DisposeHandle (my_handle);
2657 return value;
2658 #endif /* not TARGET_API_MAC_CARBON */
2662 /* set interprogram-cut-function to mac-cut-function in mac-win.el
2663 to enable Emacs to write the top of the kill-ring to the Mac clipboard. */
2664 DEFUN ("mac-cut-function", Fmac_cut_function, Smac_cut_function, 1, 2, 0,
2665 doc: /* Put the value of the string parameter to the Mac clipboard. */)
2666 (value, push)
2667 Lisp_Object value, push;
2669 char *buf;
2670 int len, i;
2672 /* fixme: ignore the push flag for now */
2674 CHECK_STRING (value);
2676 len = SCHARS (value);
2677 buf = (char *) alloca (len+1);
2678 bcopy (SDATA (value), buf, len);
2679 buf[len] = '\0';
2681 /* convert to Mac-style eol's before sending to clipboard */
2682 for (i = 0; i < len; i++)
2683 if (buf[i] == '\n')
2684 buf[i] = '\r';
2686 #if TARGET_API_MAC_CARBON
2688 ScrapRef scrap;
2689 ClearCurrentScrap ();
2690 if (GetCurrentScrap (&scrap) != noErr)
2691 error ("cannot get current scrap");
2693 if (PutScrapFlavor (scrap, kScrapFlavorTypeText, kScrapFlavorMaskNone, len,
2694 buf) != noErr)
2695 error ("cannot put to scrap");
2697 #else /* not TARGET_API_MAC_CARBON */
2698 ZeroScrap ();
2699 PutScrap (len, 'TEXT', buf);
2700 #endif /* not TARGET_API_MAC_CARBON */
2702 return Qnil;
2706 DEFUN ("x-selection-exists-p", Fx_selection_exists_p, Sx_selection_exists_p,
2707 0, 1, 0,
2708 doc: /* Whether there is an owner for the given X Selection.
2709 The arg should be the name of the selection in question, typically one of
2710 the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.
2711 \(Those are literal upper-case symbol names, since that's what X expects.)
2712 For convenience, the symbol nil is the same as `PRIMARY',
2713 and t is the same as `SECONDARY'. */)
2714 (selection)
2715 Lisp_Object selection;
2717 CHECK_SYMBOL (selection);
2719 /* Return nil for PRIMARY and SECONDARY selections; for CLIPBOARD, check
2720 if the clipboard currently has valid text format contents. */
2722 if (EQ (selection, QCLIPBOARD))
2724 Lisp_Object val = Qnil;
2726 #if TARGET_API_MAC_CARBON
2727 ScrapRef scrap;
2728 ScrapFlavorFlags sff;
2730 if (GetCurrentScrap (&scrap) == noErr)
2731 if (GetScrapFlavorFlags (scrap, kScrapFlavorTypeText, &sff) == noErr)
2732 val = Qt;
2733 #else /* not TARGET_API_MAC_CARBON */
2734 Handle my_handle;
2735 long rc, scrap_offset;
2737 my_handle = NewHandle (0);
2739 rc = GetScrap (my_handle, 'TEXT', &scrap_offset);
2740 if (rc >= 0)
2741 val = Qt;
2743 DisposeHandle (my_handle);
2744 #endif /* not TARGET_API_MAC_CARBON */
2746 return val;
2748 return Qnil;
2751 #ifdef MAC_OSX
2752 #undef select
2754 extern int inhibit_window_system;
2755 extern int noninteractive;
2757 /* When Emacs is started from the Finder, SELECT always immediately
2758 returns as if input is present when file descriptor 0 is polled for
2759 input. Strangely, when Emacs is run as a GUI application from the
2760 command line, it blocks in the same situation. This `wrapper' of
2761 the system call SELECT corrects this discrepancy. */
2763 sys_select (n, rfds, wfds, efds, timeout)
2764 int n;
2765 SELECT_TYPE *rfds;
2766 SELECT_TYPE *wfds;
2767 SELECT_TYPE *efds;
2768 struct timeval *timeout;
2770 if (!inhibit_window_system && rfds && FD_ISSET (0, rfds))
2771 return 1;
2772 else if (inhibit_window_system || noninteractive ||
2773 (timeout && (EMACS_SECS(*timeout)==0) &&
2774 (EMACS_USECS(*timeout)==0)))
2775 return select(n, rfds, wfds, efds, timeout);
2776 else
2778 EMACS_TIME end_time, now;
2780 EMACS_GET_TIME (end_time);
2781 if (timeout)
2782 EMACS_ADD_TIME (end_time, end_time, *timeout);
2786 int r;
2787 EMACS_TIME one_second;
2788 SELECT_TYPE orfds;
2790 FD_ZERO (&orfds);
2791 if (rfds)
2793 orfds = *rfds;
2796 EMACS_SET_SECS (one_second, 1);
2797 EMACS_SET_USECS (one_second, 0);
2799 if (timeout && EMACS_TIME_LT(*timeout, one_second))
2800 one_second = *timeout;
2802 if ((r = select (n, &orfds, wfds, efds, &one_second)) > 0)
2804 *rfds = orfds;
2805 return r;
2808 mac_check_for_quit_char();
2810 EMACS_GET_TIME (now);
2811 EMACS_SUB_TIME (now, end_time, now);
2813 while (!timeout || !EMACS_TIME_NEG_P (now));
2815 return 0;
2819 #undef read
2820 int sys_read (fds, buf, nbyte)
2821 int fds;
2822 char *buf;
2823 unsigned int nbyte;
2825 SELECT_TYPE rfds;
2826 EMACS_TIME one_second;
2827 int r;
2829 /* Use select to block on IO while still checking for quit_char */
2830 if (!inhibit_window_system && !noninteractive &&
2831 ! (fcntl(fds, F_GETFL, 0) & O_NONBLOCK))
2833 FD_ZERO (&rfds);
2834 FD_SET (fds, &rfds);
2835 if (sys_select (fds+1, &rfds, 0, 0, NULL) < 0)
2836 return -1;
2839 return read (fds, buf, nbyte);
2843 /* Set up environment variables so that Emacs can correctly find its
2844 support files when packaged as an application bundle. Directories
2845 placed in /usr/local/share/emacs/<emacs-version>/, /usr/local/bin,
2846 and /usr/local/libexec/emacs/<emacs-version>/<system-configuration>
2847 by `make install' by default can instead be placed in
2848 .../Emacs.app/Contents/Resources/ and
2849 .../Emacs.app/Contents/MacOS/. Each of these environment variables
2850 is changed only if it is not already set. Presumably if the user
2851 sets an environment variable, he will want to use files in his path
2852 instead of ones in the application bundle. */
2853 void
2854 init_mac_osx_environment ()
2856 CFBundleRef bundle;
2857 CFURLRef bundleURL;
2858 CFStringRef cf_app_bundle_pathname;
2859 int app_bundle_pathname_len;
2860 char *app_bundle_pathname;
2861 char *p, *q;
2862 struct stat st;
2864 /* Fetch the pathname of the application bundle as a C string into
2865 app_bundle_pathname. */
2867 bundle = CFBundleGetMainBundle ();
2868 if (!bundle)
2869 return;
2871 bundleURL = CFBundleCopyBundleURL (bundle);
2872 if (!bundleURL)
2873 return;
2875 cf_app_bundle_pathname = CFURLCopyFileSystemPath (bundleURL,
2876 kCFURLPOSIXPathStyle);
2877 app_bundle_pathname_len = CFStringGetLength (cf_app_bundle_pathname);
2878 app_bundle_pathname = (char *) alloca (app_bundle_pathname_len + 1);
2880 if (!CFStringGetCString (cf_app_bundle_pathname,
2881 app_bundle_pathname,
2882 app_bundle_pathname_len + 1,
2883 kCFStringEncodingISOLatin1))
2885 CFRelease (cf_app_bundle_pathname);
2886 return;
2889 CFRelease (cf_app_bundle_pathname);
2891 /* P should have sufficient room for the pathname of the bundle plus
2892 the subpath in it leading to the respective directories. Q
2893 should have three times that much room because EMACSLOADPATH can
2894 have the value "<path to lisp dir>:<path to leim dir>:<path to
2895 site-lisp dir>". */
2896 p = (char *) alloca (app_bundle_pathname_len + 50);
2897 q = (char *) alloca (3 * app_bundle_pathname_len + 150);
2898 if (!getenv ("EMACSLOADPATH"))
2900 q[0] = '\0';
2902 strcpy (p, app_bundle_pathname);
2903 strcat (p, "/Contents/Resources/lisp");
2904 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
2905 strcat (q, p);
2907 strcpy (p, app_bundle_pathname);
2908 strcat (p, "/Contents/Resources/leim");
2909 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
2911 if (q[0] != '\0')
2912 strcat (q, ":");
2913 strcat (q, p);
2916 strcpy (p, app_bundle_pathname);
2917 strcat (p, "/Contents/Resources/site-lisp");
2918 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
2920 if (q[0] != '\0')
2921 strcat (q, ":");
2922 strcat (q, p);
2925 if (q[0] != '\0')
2926 setenv ("EMACSLOADPATH", q, 1);
2929 if (!getenv ("EMACSPATH"))
2931 q[0] = '\0';
2933 strcpy (p, app_bundle_pathname);
2934 strcat (p, "/Contents/MacOS/libexec");
2935 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
2936 strcat (q, p);
2938 strcpy (p, app_bundle_pathname);
2939 strcat (p, "/Contents/MacOS/bin");
2940 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
2942 if (q[0] != '\0')
2943 strcat (q, ":");
2944 strcat (q, p);
2947 if (q[0] != '\0')
2948 setenv ("EMACSPATH", q, 1);
2951 if (!getenv ("EMACSDATA"))
2953 strcpy (p, app_bundle_pathname);
2954 strcat (p, "/Contents/Resources/etc");
2955 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
2956 setenv ("EMACSDATA", p, 1);
2959 if (!getenv ("EMACSDOC"))
2961 strcpy (p, app_bundle_pathname);
2962 strcat (p, "/Contents/Resources/etc");
2963 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
2964 setenv ("EMACSDOC", p, 1);
2967 if (!getenv ("INFOPATH"))
2969 strcpy (p, app_bundle_pathname);
2970 strcat (p, "/Contents/Resources/info");
2971 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
2972 setenv ("INFOPATH", p, 1);
2975 #endif /* MAC_OSX */
2977 void
2978 syms_of_mac ()
2980 QCLIPBOARD = intern ("CLIPBOARD");
2981 staticpro (&QCLIPBOARD);
2983 defsubr (&Smac_paste_function);
2984 defsubr (&Smac_cut_function);
2985 defsubr (&Sx_selection_exists_p);
2987 defsubr (&Sdo_applescript);
2988 defsubr (&Smac_file_name_to_posix);
2989 defsubr (&Sposix_file_name_to_mac);