(ispell-word): Don't alter args; set them only thru `interactive' spec.
[emacs.git] / src / mac.c
blob91d073725780ba906330a30fc35c32237cb6bd68
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 #ifndef MAC_OSX
267 /* The following functions with "sys_" prefix are stubs to Unix
268 functions that have already been implemented by CW or MPW. The
269 calls to them in Emacs source course are #define'd to call the sys_
270 versions by the header files s-mac.h. In these stubs pathnames are
271 converted between their Unix and Mac forms. */
274 /* Unix epoch is Jan 1, 1970 while Mac epoch is Jan 1, 1904: 66 years
275 + 17 leap days. These are for adjusting time values returned by
276 MacOS Toolbox functions. */
278 #define MAC_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
280 #ifdef __MWERKS__
281 #if __MSL__ < 0x6000
282 /* CW Pro 5 epoch is Jan 1, 1900 (aaarghhhhh!); remember, 1900 is not
283 a leap year! This is for adjusting time_t values returned by MSL
284 functions. */
285 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 70 + 17) * 24 * 60 * 60)
286 #else /* __MSL__ >= 0x6000 */
287 /* CW changes Pro 6 to follow Unix! */
288 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
289 #endif /* __MSL__ >= 0x6000 */
290 #elif __MRC__
291 /* MPW library functions follow Unix (confused?). */
292 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
293 #else /* not __MRC__ */
294 You lose!!!
295 #endif /* not __MRC__ */
298 /* Define our own stat function for both MrC and CW. The reason for
299 doing this: "stat" is both the name of a struct and function name:
300 can't use the same trick like that for sys_open, sys_close, etc. to
301 redirect Emacs's calls to our own version that converts Unix style
302 filenames to Mac style filename because all sorts of compilation
303 errors will be generated if stat is #define'd to be sys_stat. */
306 stat_noalias (const char *path, struct stat *buf)
308 char mac_pathname[MAXPATHLEN+1];
309 CInfoPBRec cipb;
311 if (posix_to_mac_pathname (path, mac_pathname, MAXPATHLEN+1) == 0)
312 return -1;
314 c2pstr (mac_pathname);
315 cipb.hFileInfo.ioNamePtr = mac_pathname;
316 cipb.hFileInfo.ioVRefNum = 0;
317 cipb.hFileInfo.ioDirID = 0;
318 cipb.hFileInfo.ioFDirIndex = 0;
319 /* set to 0 to get information about specific dir or file */
321 errno = PBGetCatInfo (&cipb, false);
322 if (errno == -43) /* -43: fnfErr defined in Errors.h */
323 errno = ENOENT;
324 if (errno != noErr)
325 return -1;
327 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* bit 4 = 1 for directories */
329 buf->st_mode = S_IFDIR | S_IREAD | S_IEXEC;
331 if (!(cipb.hFileInfo.ioFlAttrib & 0x1))
332 buf->st_mode |= S_IWRITE; /* bit 1 = 1 for locked files/directories */
333 buf->st_ino = cipb.dirInfo.ioDrDirID;
334 buf->st_dev = cipb.dirInfo.ioVRefNum;
335 buf->st_size = cipb.dirInfo.ioDrNmFls;
336 /* size of dir = number of files and dirs */
337 buf->st_atime
338 = buf->st_mtime
339 = cipb.dirInfo.ioDrMdDat - MAC_UNIX_EPOCH_DIFF;
340 buf->st_ctime = cipb.dirInfo.ioDrCrDat - MAC_UNIX_EPOCH_DIFF;
342 else
344 buf->st_mode = S_IFREG | S_IREAD;
345 if (!(cipb.hFileInfo.ioFlAttrib & 0x1))
346 buf->st_mode |= S_IWRITE; /* bit 1 = 1 for locked files/directories */
347 if (cipb.hFileInfo.ioFlFndrInfo.fdType == 'APPL')
348 buf->st_mode |= S_IEXEC;
349 buf->st_ino = cipb.hFileInfo.ioDirID;
350 buf->st_dev = cipb.hFileInfo.ioVRefNum;
351 buf->st_size = cipb.hFileInfo.ioFlLgLen;
352 buf->st_atime
353 = buf->st_mtime
354 = cipb.hFileInfo.ioFlMdDat - MAC_UNIX_EPOCH_DIFF;
355 buf->st_ctime = cipb.hFileInfo.ioFlCrDat - MAC_UNIX_EPOCH_DIFF;
358 if (cipb.hFileInfo.ioFlFndrInfo.fdFlags & 0x8000)
360 /* identify alias files as symlinks */
361 buf->st_mode &= ~S_IFREG;
362 buf->st_mode |= S_IFLNK;
365 buf->st_nlink = 1;
366 buf->st_uid = getuid ();
367 buf->st_gid = getgid ();
368 buf->st_rdev = 0;
370 return 0;
375 lstat (const char *path, struct stat *buf)
377 int result;
378 char true_pathname[MAXPATHLEN+1];
380 /* Try looking for the file without resolving aliases first. */
381 if ((result = stat_noalias (path, buf)) >= 0)
382 return result;
384 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
385 return -1;
387 return stat_noalias (true_pathname, buf);
392 stat (const char *path, struct stat *sb)
394 int result;
395 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
396 int len;
398 if ((result = stat_noalias (path, sb)) >= 0 &&
399 ! (sb->st_mode & S_IFLNK))
400 return result;
402 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
403 return -1;
405 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
406 if (len > -1)
408 fully_resolved_name[len] = '\0';
409 /* in fact our readlink terminates strings */
410 return lstat (fully_resolved_name, sb);
412 else
413 return lstat (true_pathname, sb);
417 #if __MRC__
418 /* CW defines fstat in stat.mac.c while MPW does not provide this
419 function. Without the information of how to get from a file
420 descriptor in MPW StdCLib to a Mac OS file spec, it should be hard
421 to implement this function. Fortunately, there is only one place
422 where this function is called in our configuration: in fileio.c,
423 where only the st_dev and st_ino fields are used to determine
424 whether two fildes point to different i-nodes to prevent copying
425 a file onto itself equal. What we have here probably needs
426 improvement. */
429 fstat (int fildes, struct stat *buf)
431 buf->st_dev = 0;
432 buf->st_ino = fildes;
433 buf->st_mode = S_IFREG; /* added by T.I. for the copy-file */
434 return 0; /* success */
436 #endif /* __MRC__ */
440 mkdir (const char *dirname, int mode)
442 #pragma unused(mode)
444 HFileParam hfpb;
445 char true_pathname[MAXPATHLEN+1], mac_pathname[MAXPATHLEN+1];
447 if (find_true_pathname (dirname, true_pathname, MAXPATHLEN+1) == -1)
448 return -1;
450 if (posix_to_mac_pathname (true_pathname, mac_pathname, MAXPATHLEN+1) == 0)
451 return -1;
453 c2pstr (mac_pathname);
454 hfpb.ioNamePtr = mac_pathname;
455 hfpb.ioVRefNum = 0; /* ignored unless name is invalid */
456 hfpb.ioDirID = 0; /* parent is the root */
458 errno = PBDirCreate ((HParmBlkPtr) &hfpb, false);
459 /* just return the Mac OSErr code for now */
460 return errno == noErr ? 0 : -1;
464 #undef rmdir
465 sys_rmdir (const char *dirname)
467 HFileParam hfpb;
468 char mac_pathname[MAXPATHLEN+1];
470 if (posix_to_mac_pathname (dirname, mac_pathname, MAXPATHLEN+1) == 0)
471 return -1;
473 c2pstr (mac_pathname);
474 hfpb.ioNamePtr = mac_pathname;
475 hfpb.ioVRefNum = 0; /* ignored unless name is invalid */
476 hfpb.ioDirID = 0; /* parent is the root */
478 errno = PBHDelete ((HParmBlkPtr) &hfpb, false);
479 return errno == noErr ? 0 : -1;
483 #ifdef __MRC__
484 /* No implementation yet. */
486 execvp (const char *path, ...)
488 return -1;
490 #endif /* __MRC__ */
494 utime (const char *path, const struct utimbuf *times)
496 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
497 int len;
498 char mac_pathname[MAXPATHLEN+1];
499 CInfoPBRec cipb;
501 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
502 return -1;
504 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
505 if (len > -1)
506 fully_resolved_name[len] = '\0';
507 else
508 strcpy (fully_resolved_name, true_pathname);
510 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
511 return -1;
513 c2pstr (mac_pathname);
514 cipb.hFileInfo.ioNamePtr = mac_pathname;
515 cipb.hFileInfo.ioVRefNum = 0;
516 cipb.hFileInfo.ioDirID = 0;
517 cipb.hFileInfo.ioFDirIndex = 0;
518 /* set to 0 to get information about specific dir or file */
520 errno = PBGetCatInfo (&cipb, false);
521 if (errno != noErr)
522 return -1;
524 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* bit 4 = 1 for directories */
526 if (times)
527 cipb.dirInfo.ioDrMdDat = times->modtime + MAC_UNIX_EPOCH_DIFF;
528 else
529 GetDateTime (&cipb.dirInfo.ioDrMdDat);
531 else
533 if (times)
534 cipb.hFileInfo.ioFlMdDat = times->modtime + MAC_UNIX_EPOCH_DIFF;
535 else
536 GetDateTime (&cipb.hFileInfo.ioFlMdDat);
539 errno = PBSetCatInfo (&cipb, false);
540 return errno == noErr ? 0 : -1;
544 #ifndef F_OK
545 #define F_OK 0
546 #endif
547 #ifndef X_OK
548 #define X_OK 1
549 #endif
550 #ifndef W_OK
551 #define W_OK 2
552 #endif
554 /* Like stat, but test for access mode in hfpb.ioFlAttrib */
556 access (const char *path, int mode)
558 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
559 int len;
560 char mac_pathname[MAXPATHLEN+1];
561 CInfoPBRec cipb;
563 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
564 return -1;
566 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
567 if (len > -1)
568 fully_resolved_name[len] = '\0';
569 else
570 strcpy (fully_resolved_name, true_pathname);
572 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
573 return -1;
575 c2pstr (mac_pathname);
576 cipb.hFileInfo.ioNamePtr = mac_pathname;
577 cipb.hFileInfo.ioVRefNum = 0;
578 cipb.hFileInfo.ioDirID = 0;
579 cipb.hFileInfo.ioFDirIndex = 0;
580 /* set to 0 to get information about specific dir or file */
582 errno = PBGetCatInfo (&cipb, false);
583 if (errno != noErr)
584 return -1;
586 if (mode == F_OK) /* got this far, file exists */
587 return 0;
589 if (mode & X_OK)
590 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* path refers to a directory */
591 return 0;
592 else
594 if (cipb.hFileInfo.ioFlFndrInfo.fdType == 'APPL')
595 return 0;
596 else
597 return -1;
600 if (mode & W_OK)
601 return (cipb.hFileInfo.ioFlAttrib & 0x1) ? -1 : 0;
602 /* don't allow if lock bit is on */
604 return -1;
608 #define DEV_NULL_FD 0x10000
610 #undef open
612 sys_open (const char *path, int oflag)
614 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
615 int len;
616 char mac_pathname[MAXPATHLEN+1];
618 if (strcmp (path, "/dev/null") == 0)
619 return DEV_NULL_FD; /* some bogus fd to be ignored in write */
621 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
622 return -1;
624 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
625 if (len > -1)
626 fully_resolved_name[len] = '\0';
627 else
628 strcpy (fully_resolved_name, true_pathname);
630 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
631 return -1;
632 else
634 #ifdef __MRC__
635 int res = open (mac_pathname, oflag);
636 /* if (oflag == O_WRONLY || oflag == O_RDWR) */
637 if (oflag & O_CREAT)
638 fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
639 return res;
640 #else /* not __MRC__ */
641 return open (mac_pathname, oflag);
642 #endif /* not __MRC__ */
647 #undef creat
649 sys_creat (const char *path, mode_t mode)
651 char true_pathname[MAXPATHLEN+1];
652 int len;
653 char mac_pathname[MAXPATHLEN+1];
655 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
656 return -1;
658 if (!posix_to_mac_pathname (true_pathname, mac_pathname, MAXPATHLEN+1))
659 return -1;
660 else
662 #ifdef __MRC__
663 int result = creat (mac_pathname);
664 fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
665 return result;
666 #else /* not __MRC__ */
667 return creat (mac_pathname, mode);
668 #endif /* not __MRC__ */
673 #undef unlink
675 sys_unlink (const char *path)
677 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
678 int len;
679 char mac_pathname[MAXPATHLEN+1];
681 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
682 return -1;
684 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
685 if (len > -1)
686 fully_resolved_name[len] = '\0';
687 else
688 strcpy (fully_resolved_name, true_pathname);
690 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
691 return -1;
692 else
693 return unlink (mac_pathname);
697 #undef read
699 sys_read (int fildes, char *buf, int count)
701 if (fildes == 0) /* this should not be used for console input */
702 return -1;
703 else
704 #if __MSL__ >= 0x6000
705 return _read (fildes, buf, count);
706 #else
707 return read (fildes, buf, count);
708 #endif
712 #undef write
714 sys_write (int fildes, const char *buf, int count)
716 if (fildes == DEV_NULL_FD)
717 return count;
718 else
719 #if __MSL__ >= 0x6000
720 return _write (fildes, buf, count);
721 #else
722 return write (fildes, buf, count);
723 #endif
727 #undef rename
729 sys_rename (const char * old_name, const char * new_name)
731 char true_old_pathname[MAXPATHLEN+1], true_new_pathname[MAXPATHLEN+1];
732 char fully_resolved_old_name[MAXPATHLEN+1];
733 int len;
734 char mac_old_name[MAXPATHLEN+1], mac_new_name[MAXPATHLEN+1];
736 if (find_true_pathname (old_name, true_old_pathname, MAXPATHLEN+1) == -1)
737 return -1;
739 len = readlink (true_old_pathname, fully_resolved_old_name, MAXPATHLEN);
740 if (len > -1)
741 fully_resolved_old_name[len] = '\0';
742 else
743 strcpy (fully_resolved_old_name, true_old_pathname);
745 if (find_true_pathname (new_name, true_new_pathname, MAXPATHLEN+1) == -1)
746 return -1;
748 if (strcmp (fully_resolved_old_name, true_new_pathname) == 0)
749 return 0;
751 if (!posix_to_mac_pathname (fully_resolved_old_name,
752 mac_old_name,
753 MAXPATHLEN+1))
754 return -1;
756 if (!posix_to_mac_pathname(true_new_pathname, mac_new_name, MAXPATHLEN+1))
757 return -1;
759 /* If a file with new_name already exists, rename deletes the old
760 file in Unix. CW version fails in these situation. So we add a
761 call to unlink here. */
762 (void) unlink (mac_new_name);
764 return rename (mac_old_name, mac_new_name);
768 #undef fopen
769 extern FILE *fopen (const char *name, const char *mode);
770 FILE *
771 sys_fopen (const char *name, const char *mode)
773 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
774 int len;
775 char mac_pathname[MAXPATHLEN+1];
777 if (find_true_pathname (name, true_pathname, MAXPATHLEN+1) == -1)
778 return 0;
780 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
781 if (len > -1)
782 fully_resolved_name[len] = '\0';
783 else
784 strcpy (fully_resolved_name, true_pathname);
786 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
787 return 0;
788 else
790 #ifdef __MRC__
791 if (mode[0] == 'w' || mode[0] == 'a')
792 fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
793 #endif /* not __MRC__ */
794 return fopen (mac_pathname, mode);
799 #include <Events.h>
801 long target_ticks = 0;
803 #ifdef __MRC__
804 __sigfun alarm_signal_func = (__sigfun) 0;
805 #elif __MWERKS__
806 __signal_func_ptr alarm_signal_func = (__signal_func_ptr) 0;
807 #else /* not __MRC__ and not __MWERKS__ */
808 You lose!!!
809 #endif /* not __MRC__ and not __MWERKS__ */
812 /* These functions simulate SIG_ALRM. The stub for function signal
813 stores the signal handler function in alarm_signal_func if a
814 SIG_ALRM is encountered. check_alarm is called in XTread_socket,
815 which emacs calls periodically. A pending alarm is represented by
816 a non-zero target_ticks value. check_alarm calls the handler
817 function pointed to by alarm_signal_func if one has been set up and
818 an alarm is pending. */
820 void
821 check_alarm ()
823 if (target_ticks && TickCount () > target_ticks)
825 target_ticks = 0;
826 if (alarm_signal_func)
827 (*alarm_signal_func)(SIGALRM);
833 select (n, rfds, wfds, efds, timeout)
834 int n;
835 SELECT_TYPE *rfds;
836 SELECT_TYPE *wfds;
837 SELECT_TYPE *efds;
838 struct timeval *timeout;
840 #ifdef TARGET_API_MAC_CARBON
841 return 1;
842 #else /* not TARGET_API_MAC_CARBON */
843 EMACS_TIME end_time, now;
844 EventRecord e;
846 /* Can only handle wait for keyboard input. */
847 if (n > 1 || wfds || efds)
848 return -1;
850 EMACS_GET_TIME (end_time);
851 EMACS_ADD_TIME (end_time, end_time, *timeout);
855 /* Also return true if an event other than a keyDown has
856 occurred. This causes kbd_buffer_get_event in keyboard.c to
857 call read_avail_input which in turn calls XTread_socket to
858 poll for these events. Otherwise these never get processed
859 except but a very slow poll timer. */
860 if (FD_ISSET (0, rfds) && EventAvail (everyEvent, &e))
861 return 1;
863 /* Also check movement of the mouse. */
865 Point mouse_pos;
866 static Point old_mouse_pos = {-1, -1};
868 GetMouse (&mouse_pos);
869 if (!EqualPt (mouse_pos, old_mouse_pos))
871 old_mouse_pos = mouse_pos;
872 return 1;
876 WaitNextEvent (0, &e, 1UL, NULL); /* Accept no event; wait 1
877 tic. by T.I. */
879 EMACS_GET_TIME (now);
880 EMACS_SUB_TIME (now, end_time, now);
882 while (!EMACS_TIME_NEG_P (now));
884 return 0;
885 #endif /* not TARGET_API_MAC_CARBON */
889 /* Called in sys_select to wait for an alarm signal to arrive. */
892 pause ()
894 EventRecord e;
895 unsigned long tick;
897 if (!target_ticks) /* no alarm pending */
898 return -1;
900 if ((tick = TickCount ()) < target_ticks)
901 WaitNextEvent (0, &e, target_ticks - tick, NULL); /* Accept no event;
902 just wait. by T.I. */
904 target_ticks = 0;
905 if (alarm_signal_func)
906 (*alarm_signal_func)(SIGALRM);
908 return 0;
913 alarm (int seconds)
915 long remaining = target_ticks ? (TickCount () - target_ticks) / 60 : 0;
917 target_ticks = seconds ? TickCount () + 60 * seconds : 0;
919 return (remaining < 0) ? 0 : (unsigned int) remaining;
923 #undef signal
924 #ifdef __MRC__
925 extern __sigfun signal (int signal, __sigfun signal_func);
926 __sigfun
927 sys_signal (int signal_num, __sigfun signal_func)
928 #elif __MWERKS__
929 extern __signal_func_ptr signal (int signal, __signal_func_ptr signal_func);
930 __signal_func_ptr
931 sys_signal (int signal_num, __signal_func_ptr signal_func)
932 #else /* not __MRC__ and not __MWERKS__ */
933 You lose!!!
934 #endif /* not __MRC__ and not __MWERKS__ */
936 if (signal_num != SIGALRM)
937 return signal (signal_num, signal_func);
938 else
940 #ifdef __MRC__
941 __sigfun old_signal_func;
942 #elif __MWERKS__
943 __signal_func_ptr old_signal_func;
944 #else
945 You lose!!!
946 #endif
947 old_signal_func = alarm_signal_func;
948 alarm_signal_func = signal_func;
949 return old_signal_func;
954 /* gettimeofday should return the amount of time (in a timeval
955 structure) since midnight today. The toolbox function Microseconds
956 returns the number of microseconds (in a UnsignedWide value) since
957 the machine was booted. Also making this complicated is WideAdd,
958 WideSubtract, etc. take wide values. */
961 gettimeofday (tp)
962 struct timeval *tp;
964 static inited = 0;
965 static wide wall_clock_at_epoch, clicks_at_epoch;
966 UnsignedWide uw_microseconds;
967 wide w_microseconds;
968 time_t sys_time (time_t *);
970 /* If this function is called for the first time, record the number
971 of seconds since midnight and the number of microseconds since
972 boot at the time of this first call. */
973 if (!inited)
975 time_t systime;
976 inited = 1;
977 systime = sys_time (NULL);
978 /* Store microseconds since midnight in wall_clock_at_epoch. */
979 WideMultiply (systime, 1000000L, &wall_clock_at_epoch);
980 Microseconds (&uw_microseconds);
981 /* Store microseconds since boot in clicks_at_epoch. */
982 clicks_at_epoch.hi = uw_microseconds.hi;
983 clicks_at_epoch.lo = uw_microseconds.lo;
986 /* Get time since boot */
987 Microseconds (&uw_microseconds);
989 /* Convert to time since midnight*/
990 w_microseconds.hi = uw_microseconds.hi;
991 w_microseconds.lo = uw_microseconds.lo;
992 WideSubtract (&w_microseconds, &clicks_at_epoch);
993 WideAdd (&w_microseconds, &wall_clock_at_epoch);
994 tp->tv_sec = WideDivide (&w_microseconds, 1000000L, &tp->tv_usec);
996 return 0;
1000 #ifdef __MRC__
1001 unsigned int
1002 sleep (unsigned int seconds)
1004 unsigned long time_up;
1005 EventRecord e;
1007 time_up = TickCount () + seconds * 60;
1008 while (TickCount () < time_up)
1010 /* Accept no event; just wait. by T.I. */
1011 WaitNextEvent (0, &e, 30, NULL);
1014 return (0);
1016 #endif /* __MRC__ */
1019 /* The time functions adjust time values according to the difference
1020 between the Unix and CW epoches. */
1022 #undef gmtime
1023 extern struct tm *gmtime (const time_t *);
1024 struct tm *
1025 sys_gmtime (const time_t *timer)
1027 time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
1029 return gmtime (&unix_time);
1033 #undef localtime
1034 extern struct tm *localtime (const time_t *);
1035 struct tm *
1036 sys_localtime (const time_t *timer)
1038 #if __MSL__ >= 0x6000
1039 time_t unix_time = *timer;
1040 #else
1041 time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
1042 #endif
1044 return localtime (&unix_time);
1048 #undef ctime
1049 extern char *ctime (const time_t *);
1050 char *
1051 sys_ctime (const time_t *timer)
1053 #if __MSL__ >= 0x6000
1054 time_t unix_time = *timer;
1055 #else
1056 time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
1057 #endif
1059 return ctime (&unix_time);
1063 #undef time
1064 extern time_t time (time_t *);
1065 time_t
1066 sys_time (time_t *timer)
1068 #if __MSL__ >= 0x6000
1069 time_t mac_time = time (NULL);
1070 #else
1071 time_t mac_time = time (NULL) - CW_OR_MPW_UNIX_EPOCH_DIFF;
1072 #endif
1074 if (timer)
1075 *timer = mac_time;
1077 return mac_time;
1081 /* MPW strftime broken for "%p" format */
1082 #ifdef __MRC__
1083 #undef strftime
1084 #include <time.h>
1085 size_t
1086 sys_strftime (char * s, size_t maxsize, const char * format,
1087 const struct tm * timeptr)
1089 if (strcmp (format, "%p") == 0)
1091 if (maxsize < 3)
1092 return 0;
1093 if (timeptr->tm_hour < 12)
1095 strcpy (s, "AM");
1096 return 2;
1098 else
1100 strcpy (s, "PM");
1101 return 2;
1104 else
1105 return strftime (s, maxsize, format, timeptr);
1107 #endif /* __MRC__ */
1110 /* no subprocesses, empty wait */
1113 wait (int pid)
1115 return 0;
1119 void
1120 croak (char *badfunc)
1122 printf ("%s not yet implemented\r\n", badfunc);
1123 exit (1);
1127 char *
1128 index (const char * str, int chr)
1130 return strchr (str, chr);
1134 char *
1135 mktemp (char *template)
1137 int len, k;
1138 static seqnum = 0;
1140 len = strlen (template);
1141 k = len - 1;
1142 while (k >= 0 && template[k] == 'X')
1143 k--;
1145 k++; /* make k index of first 'X' */
1147 if (k < len)
1149 /* Zero filled, number of digits equal to the number of X's. */
1150 sprintf (&template[k], "%0*d", len-k, seqnum++);
1152 return template;
1154 else
1155 return 0;
1159 /* Emulate getpwuid, getpwnam and others. */
1161 #define PASSWD_FIELD_SIZE 256
1163 static char my_passwd_name[PASSWD_FIELD_SIZE];
1164 static char my_passwd_dir[MAXPATHLEN+1];
1166 static struct passwd my_passwd =
1168 my_passwd_name,
1169 my_passwd_dir,
1172 static struct group my_group =
1174 /* There are no groups on the mac, so we just return "root" as the
1175 group name. */
1176 "root",
1180 /* Initialized by main () in macterm.c to pathname of emacs directory. */
1182 char emacs_passwd_dir[MAXPATHLEN+1];
1184 char *
1185 getwd (char *);
1187 void
1188 init_emacs_passwd_dir ()
1190 int found = false;
1192 if (getwd (emacs_passwd_dir) && getwd (my_passwd_dir))
1194 /* Need pathname of first ancestor that begins with "emacs"
1195 since Mac emacs application is somewhere in the emacs-*
1196 tree. */
1197 int len = strlen (emacs_passwd_dir);
1198 int j = len - 1;
1199 /* j points to the "/" following the directory name being
1200 compared. */
1201 int i = j - 1;
1202 while (i >= 0 && !found)
1204 while (i >= 0 && emacs_passwd_dir[i] != '/')
1205 i--;
1206 if (emacs_passwd_dir[i] == '/' && i+5 < len)
1207 found = (strncmp (&(emacs_passwd_dir[i+1]), "emacs", 5) == 0);
1208 if (found)
1209 emacs_passwd_dir[j+1] = '\0';
1210 else
1212 j = i;
1213 i = j - 1;
1218 if (!found)
1220 /* Setting to "/" probably won't work but set it to something
1221 anyway. */
1222 strcpy (emacs_passwd_dir, "/");
1223 strcpy (my_passwd_dir, "/");
1228 static struct passwd emacs_passwd =
1230 "emacs",
1231 emacs_passwd_dir,
1234 static int my_passwd_inited = 0;
1237 static void
1238 init_my_passwd ()
1240 char **owner_name;
1242 /* Note: my_passwd_dir initialized in int_emacs_passwd_dir to
1243 directory where Emacs was started. */
1245 owner_name = (char **) GetResource ('STR ',-16096);
1246 if (owner_name)
1248 HLock (owner_name);
1249 BlockMove ((unsigned char *) *owner_name,
1250 (unsigned char *) my_passwd_name,
1251 *owner_name[0]+1);
1252 HUnlock (owner_name);
1253 p2cstr ((unsigned char *) my_passwd_name);
1255 else
1256 my_passwd_name[0] = 0;
1260 struct passwd *
1261 getpwuid (uid_t uid)
1263 if (!my_passwd_inited)
1265 init_my_passwd ();
1266 my_passwd_inited = 1;
1269 return &my_passwd;
1273 struct group *
1274 getgrgid (gid_t gid)
1276 return &my_group;
1280 struct passwd *
1281 getpwnam (const char *name)
1283 if (strcmp (name, "emacs") == 0)
1284 return &emacs_passwd;
1286 if (!my_passwd_inited)
1288 init_my_passwd ();
1289 my_passwd_inited = 1;
1292 return &my_passwd;
1296 /* The functions fork, kill, sigsetmask, sigblock, request_sigio,
1297 setpgrp, setpriority, and unrequest_sigio are defined to be empty
1298 as in msdos.c. */
1302 fork ()
1304 return -1;
1309 kill (int x, int y)
1311 return -1;
1315 void
1316 sys_subshell ()
1318 error ("Can't spawn subshell");
1323 sigsetmask (int x)
1325 return 0;
1330 sigblock (int mask)
1332 return 0;
1336 void
1337 request_sigio (void)
1342 void
1343 unrequest_sigio (void)
1349 setpgrp ()
1351 return 0;
1355 /* No pipes yet. */
1358 pipe (int _fildes[2])
1360 errno = EACCES;
1361 return -1;
1365 /* Hard and symbolic links. */
1368 symlink (const char *name1, const char *name2)
1370 errno = ENOENT;
1371 return -1;
1376 link (const char *name1, const char *name2)
1378 errno = ENOENT;
1379 return -1;
1382 #endif /* ! MAC_OSX */
1384 /* Determine the path name of the file specified by VREFNUM, DIRID,
1385 and NAME and place that in the buffer PATH of length
1386 MAXPATHLEN. */
1388 path_from_vol_dir_name (char *path, int man_path_len, short vol_ref_num,
1389 long dir_id, ConstStr255Param name)
1391 Str255 dir_name;
1392 CInfoPBRec cipb;
1393 OSErr err;
1395 if (strlen (name) > man_path_len)
1396 return 0;
1398 memcpy (dir_name, name, name[0]+1);
1399 memcpy (path, name, name[0]+1);
1400 p2cstr (path);
1402 cipb.dirInfo.ioDrParID = dir_id;
1403 cipb.dirInfo.ioNamePtr = dir_name;
1407 cipb.dirInfo.ioVRefNum = vol_ref_num;
1408 cipb.dirInfo.ioFDirIndex = -1;
1409 cipb.dirInfo.ioDrDirID = cipb.dirInfo.ioDrParID;
1410 /* go up to parent each time */
1412 err = PBGetCatInfo (&cipb, false);
1413 if (err != noErr)
1414 return 0;
1416 p2cstr (dir_name);
1417 if (strlen (dir_name) + strlen (path) + 1 >= man_path_len)
1418 return 0;
1420 strcat (dir_name, ":");
1421 strcat (dir_name, path);
1422 /* attach to front since we're going up directory tree */
1423 strcpy (path, dir_name);
1425 while (cipb.dirInfo.ioDrDirID != fsRtDirID);
1426 /* stop when we see the volume's root directory */
1428 return 1; /* success */
1431 #ifndef MAC_OSX
1434 readlink (const char *path, char *buf, int bufsiz)
1436 char mac_sym_link_name[MAXPATHLEN+1];
1437 OSErr err;
1438 FSSpec fsspec;
1439 Boolean target_is_folder, was_aliased;
1440 Str255 directory_name, mac_pathname;
1441 CInfoPBRec cipb;
1443 if (posix_to_mac_pathname (path, mac_sym_link_name, MAXPATHLEN+1) == 0)
1444 return -1;
1446 c2pstr (mac_sym_link_name);
1447 err = FSMakeFSSpec (0, 0, mac_sym_link_name, &fsspec);
1448 if (err != noErr)
1450 errno = ENOENT;
1451 return -1;
1454 err = ResolveAliasFile (&fsspec, true, &target_is_folder, &was_aliased);
1455 if (err != noErr || !was_aliased)
1457 errno = ENOENT;
1458 return -1;
1461 if (path_from_vol_dir_name (mac_pathname, 255, fsspec.vRefNum, fsspec.parID,
1462 fsspec.name) == 0)
1464 errno = ENOENT;
1465 return -1;
1468 if (mac_to_posix_pathname (mac_pathname, buf, bufsiz) == 0)
1470 errno = ENOENT;
1471 return -1;
1474 return strlen (buf);
1478 /* Convert a path to one with aliases fully expanded. */
1480 static int
1481 find_true_pathname (const char *path, char *buf, int bufsiz)
1483 char *q, temp[MAXPATHLEN+1];
1484 const char *p;
1485 int len;
1487 if (bufsiz <= 0 || path == 0 || path[0] == '\0')
1488 return -1;
1490 buf[0] = '\0';
1492 p = path;
1493 if (*p == '/')
1494 q = strchr (p + 1, '/');
1495 else
1496 q = strchr (p, '/');
1497 len = 0; /* loop may not be entered, e.g., for "/" */
1499 while (q)
1501 strcpy (temp, buf);
1502 strncat (temp, p, q - p);
1503 len = readlink (temp, buf, bufsiz);
1504 if (len <= -1)
1506 if (strlen (temp) + 1 > bufsiz)
1507 return -1;
1508 strcpy (buf, temp);
1510 strcat (buf, "/");
1511 len++;
1512 p = q + 1;
1513 q = strchr(p, '/');
1516 if (len + strlen (p) + 1 >= bufsiz)
1517 return -1;
1519 strcat (buf, p);
1520 return len + strlen (p);
1524 mode_t
1525 umask (mode_t numask)
1527 static mode_t mask = 022;
1528 mode_t oldmask = mask;
1529 mask = numask;
1530 return oldmask;
1535 chmod (const char *path, mode_t mode)
1537 /* say it always succeed for now */
1538 return 0;
1543 dup (int oldd)
1545 #ifdef __MRC__
1546 return fcntl (oldd, F_DUPFD, 0);
1547 #elif __MWERKS__
1548 /* current implementation of fcntl in fcntl.mac.c simply returns old
1549 descriptor */
1550 return fcntl (oldd, F_DUPFD);
1551 #else
1552 You lose!!!
1553 #endif
1557 /* This is from the original sysdep.c. Emulate BSD dup2. First close
1558 newd if it already exists. Then, attempt to dup oldd. If not
1559 successful, call dup2 recursively until we are, then close the
1560 unsuccessful ones. */
1563 dup2 (int oldd, int newd)
1565 int fd, ret;
1567 close (newd);
1569 fd = dup (oldd);
1570 if (fd == -1)
1571 return -1;
1572 if (fd == newd)
1573 return newd;
1574 ret = dup2 (oldd, newd);
1575 close (fd);
1576 return ret;
1580 /* let it fail for now */
1582 char *
1583 sbrk (int incr)
1585 return (char *) -1;
1590 fsync (int fd)
1592 return 0;
1597 ioctl (int d, int request, void *argp)
1599 return -1;
1603 #ifdef __MRC__
1605 isatty (int fildes)
1607 if (fildes >=0 && fildes <= 2)
1608 return 1;
1609 else
1610 return 0;
1615 getgid ()
1617 return 100;
1622 getegid ()
1624 return 100;
1629 getuid ()
1631 return 200;
1636 geteuid ()
1638 return 200;
1640 #endif /* __MRC__ */
1643 #ifdef __MWERKS__
1644 #if __MSL__ < 0x6000
1645 #undef getpid
1647 getpid ()
1649 return 9999;
1651 #endif
1652 #endif /* __MWERKS__ */
1654 #endif /* ! MAC_OSX */
1657 /* Return the path to the directory in which Emacs can create
1658 temporary files. The MacOS "temporary items" directory cannot be
1659 used because it removes the file written by a process when it
1660 exits. In that sense it's more like "/dev/null" than "/tmp" (but
1661 again not exactly). And of course Emacs needs to read back the
1662 files written by its subprocesses. So here we write the files to a
1663 directory "Emacs" in the Preferences Folder. This directory is
1664 created if it does not exist. */
1666 char *
1667 get_temp_dir_name ()
1669 static char *temp_dir_name = NULL;
1670 short vol_ref_num;
1671 long dir_id;
1672 OSErr err;
1673 Str255 dir_name, full_path;
1674 CInfoPBRec cpb;
1675 char unix_dir_name[MAXPATHLEN+1];
1676 DIR *dir;
1678 /* Cache directory name with pointer temp_dir_name.
1679 Look for it only the first time. */
1680 if (!temp_dir_name)
1682 err = FindFolder (kOnSystemDisk, kPreferencesFolderType, kCreateFolder,
1683 &vol_ref_num, &dir_id);
1684 if (err != noErr)
1685 return NULL;
1687 if (!path_from_vol_dir_name (full_path, 255, vol_ref_num, dir_id, "\p"))
1688 return NULL;
1690 if (strlen (full_path) + 6 <= MAXPATHLEN)
1691 strcat (full_path, "Emacs:");
1692 else
1693 return NULL;
1695 if (!mac_to_posix_pathname (full_path, unix_dir_name, MAXPATHLEN+1))
1696 return NULL;
1698 dir = opendir (unix_dir_name); /* check whether temp directory exists */
1699 if (dir)
1700 closedir (dir);
1701 else if (mkdir (unix_dir_name, 0700) != 0) /* create it if not */
1702 return NULL;
1704 temp_dir_name = (char *) malloc (strlen (unix_dir_name) + 1);
1705 strcpy (temp_dir_name, unix_dir_name);
1708 return temp_dir_name;
1711 #ifndef MAC_OSX
1713 /* Allocate and construct an array of pointers to strings from a list
1714 of strings stored in a 'STR#' resource. The returned pointer array
1715 is stored in the style of argv and environ: if the 'STR#' resource
1716 contains numString strings, a pointer array with numString+1
1717 elements is returned in which the last entry contains a null
1718 pointer. The pointer to the pointer array is passed by pointer in
1719 parameter t. The resource ID of the 'STR#' resource is passed in
1720 parameter StringListID.
1723 void
1724 get_string_list (char ***t, short string_list_id)
1726 Handle h;
1727 Ptr p;
1728 int i, num_strings;
1730 h = GetResource ('STR#', string_list_id);
1731 if (h)
1733 HLock (h);
1734 p = *h;
1735 num_strings = * (short *) p;
1736 p += sizeof(short);
1737 *t = (char **) malloc (sizeof (char *) * (num_strings + 1));
1738 for (i = 0; i < num_strings; i++)
1740 short length = *p++;
1741 (*t)[i] = (char *) malloc (length + 1);
1742 strncpy ((*t)[i], p, length);
1743 (*t)[i][length] = '\0';
1744 p += length;
1746 (*t)[num_strings] = 0;
1747 HUnlock (h);
1749 else
1751 /* Return no string in case GetResource fails. Bug fixed by
1752 Ikegami Tsutomu. Caused MPW build to crash without sym -on
1753 option (no sym -on implies -opt local). */
1754 *t = (char **) malloc (sizeof (char *));
1755 (*t)[0] = 0;
1760 static char *
1761 get_path_to_system_folder ()
1763 short vol_ref_num;
1764 long dir_id;
1765 OSErr err;
1766 Str255 dir_name, full_path;
1767 CInfoPBRec cpb;
1768 static char system_folder_unix_name[MAXPATHLEN+1];
1769 DIR *dir;
1771 err = FindFolder (kOnSystemDisk, kSystemFolderType, kDontCreateFolder,
1772 &vol_ref_num, &dir_id);
1773 if (err != noErr)
1774 return NULL;
1776 if (!path_from_vol_dir_name (full_path, 255, vol_ref_num, dir_id, "\p"))
1777 return NULL;
1779 if (!mac_to_posix_pathname (full_path, system_folder_unix_name,
1780 MAXPATHLEN+1))
1781 return NULL;
1783 return system_folder_unix_name;
1787 char **environ;
1789 #define ENVIRON_STRING_LIST_ID 128
1791 /* Get environment variable definitions from STR# resource. */
1793 void
1794 init_environ ()
1796 int i;
1798 get_string_list (&environ, ENVIRON_STRING_LIST_ID);
1800 i = 0;
1801 while (environ[i])
1802 i++;
1804 /* Make HOME directory the one Emacs starts up in if not specified
1805 by resource. */
1806 if (getenv ("HOME") == NULL)
1808 environ = (char **) realloc (environ, sizeof (char *) * (i + 2));
1809 if (environ)
1811 environ[i] = (char *) malloc (strlen (my_passwd_dir) + 6);
1812 if (environ[i])
1814 strcpy (environ[i], "HOME=");
1815 strcat (environ[i], my_passwd_dir);
1817 environ[i+1] = 0;
1818 i++;
1822 /* Make HOME directory the one Emacs starts up in if not specified
1823 by resource. */
1824 if (getenv ("MAIL") == NULL)
1826 environ = (char **) realloc (environ, sizeof (char *) * (i + 2));
1827 if (environ)
1829 char * path_to_system_folder = get_path_to_system_folder ();
1830 environ[i] = (char *) malloc (strlen (path_to_system_folder) + 22);
1831 if (environ[i])
1833 strcpy (environ[i], "MAIL=");
1834 strcat (environ[i], path_to_system_folder);
1835 strcat (environ[i], "Eudora Folder/In");
1837 environ[i+1] = 0;
1843 /* Return the value of the environment variable NAME. */
1845 char *
1846 getenv (const char *name)
1848 int length = strlen(name);
1849 char **e;
1851 for (e = environ; *e != 0; e++)
1852 if (strncmp(*e, name, length) == 0 && (*e)[length] == '=')
1853 return &(*e)[length + 1];
1855 if (strcmp (name, "TMPDIR") == 0)
1856 return get_temp_dir_name ();
1858 return 0;
1862 #ifdef __MRC__
1863 /* see Interfaces&Libraries:Interfaces:CIncludes:signal.h */
1864 char *sys_siglist[] =
1866 "Zero is not a signal!!!",
1867 "Abort", /* 1 */
1868 "Interactive user interrupt", /* 2 */ "?",
1869 "Floating point exception", /* 4 */ "?", "?", "?",
1870 "Illegal instruction", /* 8 */ "?", "?", "?", "?", "?", "?", "?",
1871 "Segment violation", /* 16 */ "?", "?", "?", "?", "?", "?", "?",
1872 "?", "?", "?", "?", "?", "?", "?", "?",
1873 "Terminal" /* 32 */
1875 #elif __MWERKS__
1876 char *sys_siglist[] =
1878 "Zero is not a signal!!!",
1879 "Abort",
1880 "Floating point exception",
1881 "Illegal instruction",
1882 "Interactive user interrupt",
1883 "Segment violation",
1884 "Terminal"
1886 #else /* not __MRC__ and not __MWERKS__ */
1887 You lose!!!
1888 #endif /* not __MRC__ and not __MWERKS__ */
1891 #include <utsname.h>
1894 uname (struct utsname *name)
1896 char **system_name;
1897 system_name = GetString (-16413); /* IM - Resource Manager Reference */
1898 if (system_name)
1900 BlockMove (*system_name, name->nodename, (*system_name)[0]+1);
1901 p2cstr (name->nodename);
1902 return 0;
1904 else
1905 return -1;
1909 #include <Processes.h>
1910 #include <EPPC.h>
1912 /* Event class of HLE sent to subprocess. */
1913 const OSType kEmacsSubprocessSend = 'ESND';
1915 /* Event class of HLE sent back from subprocess. */
1916 const OSType kEmacsSubprocessReply = 'ERPY';
1919 char *
1920 mystrchr (char *s, char c)
1922 while (*s && *s != c)
1924 if (*s == '\\')
1925 s++;
1926 s++;
1929 if (*s)
1931 *s = '\0';
1932 return s;
1934 else
1935 return NULL;
1939 char *
1940 mystrtok (char *s)
1942 while (*s)
1943 s++;
1945 return s + 1;
1949 void
1950 mystrcpy (char *to, char *from)
1952 while (*from)
1954 if (*from == '\\')
1955 from++;
1956 *to++ = *from++;
1958 *to = '\0';
1962 /* Start a Mac subprocess. Arguments for it is passed in argv (null
1963 terminated). The process should run with the default directory
1964 "workdir", read input from "infn", and write output and error to
1965 "outfn" and "errfn", resp. The Process Manager call
1966 LaunchApplication is used to start the subprocess. We use high
1967 level events as the mechanism to pass arguments to the subprocess
1968 and to make Emacs wait for the subprocess to terminate and pass
1969 back a result code. The bulk of the code here packs the arguments
1970 into one message to be passed together with the high level event.
1971 Emacs also sometimes starts a subprocess using a shell to perform
1972 wildcard filename expansion. Since we don't really have a shell on
1973 the Mac, this case is detected and the starting of the shell is
1974 by-passed. We really need to add code here to do filename
1975 expansion to support such functionality. */
1978 run_mac_command (argv, workdir, infn, outfn, errfn)
1979 unsigned char **argv;
1980 const char *workdir;
1981 const char *infn, *outfn, *errfn;
1983 #ifdef TARGET_API_MAC_CARBON
1984 return -1;
1985 #else /* not TARGET_API_MAC_CARBON */
1986 char macappname[MAXPATHLEN+1], macworkdir[MAXPATHLEN+1];
1987 char macinfn[MAXPATHLEN+1], macoutfn[MAXPATHLEN+1], macerrfn[MAXPATHLEN+1];
1988 int paramlen, argc, newargc, j, retries;
1989 char **newargv, *param, *p;
1990 OSErr iErr;
1991 FSSpec spec;
1992 LaunchParamBlockRec lpbr;
1993 EventRecord send_event, reply_event;
1994 RgnHandle cursor_region_handle;
1995 TargetID targ;
1996 unsigned long ref_con, len;
1998 if (posix_to_mac_pathname (workdir, macworkdir, MAXPATHLEN+1) == 0)
1999 return -1;
2000 if (posix_to_mac_pathname (infn, macinfn, MAXPATHLEN+1) == 0)
2001 return -1;
2002 if (posix_to_mac_pathname (outfn, macoutfn, MAXPATHLEN+1) == 0)
2003 return -1;
2004 if (posix_to_mac_pathname (errfn, macerrfn, MAXPATHLEN+1) == 0)
2005 return -1;
2007 paramlen = strlen (macworkdir) + strlen (macinfn) + strlen (macoutfn)
2008 + strlen (macerrfn) + 4; /* count nulls at end of strings */
2010 argc = 0;
2011 while (argv[argc])
2012 argc++;
2014 if (argc == 0)
2015 return -1;
2017 /* If a subprocess is invoked with a shell, we receive 3 arguments
2018 of the form: "<path to emacs bins>/sh" "-c" "<path to emacs
2019 bins>/<command> <command args>" */
2020 j = strlen (argv[0]);
2021 if (j >= 3 && strcmp (argv[0]+j-3, "/sh") == 0
2022 && argc == 3 && strcmp (argv[1], "-c") == 0)
2024 char *command, *t, tempmacpathname[MAXPATHLEN+1];
2026 /* The arguments for the command in argv[2] are separated by
2027 spaces. Count them and put the count in newargc. */
2028 command = (char *) alloca (strlen (argv[2])+2);
2029 strcpy (command, argv[2]);
2030 if (command[strlen (command) - 1] != ' ')
2031 strcat (command, " ");
2033 t = command;
2034 newargc = 0;
2035 t = mystrchr (t, ' ');
2036 while (t)
2038 newargc++;
2039 t = mystrchr (t+1, ' ');
2042 newargv = (char **) alloca (sizeof (char *) * newargc);
2044 t = command;
2045 for (j = 0; j < newargc; j++)
2047 newargv[j] = (char *) alloca (strlen (t) + 1);
2048 mystrcpy (newargv[j], t);
2050 t = mystrtok (t);
2051 paramlen += strlen (newargv[j]) + 1;
2054 if (strncmp (newargv[0], "~emacs/", 7) == 0)
2056 if (posix_to_mac_pathname (newargv[0], tempmacpathname, MAXPATHLEN+1)
2057 == 0)
2058 return -1;
2060 else
2061 { /* sometimes Emacs call "sh" without a path for the command */
2062 #if 0
2063 char *t = (char *) alloca (strlen (newargv[0]) + 7 + 1);
2064 strcpy (t, "~emacs/");
2065 strcat (t, newargv[0]);
2066 #endif /* 0 */
2067 Lisp_Object path;
2068 openp (Vexec_path, build_string (newargv[0]), EXEC_SUFFIXES, &path,
2069 make_number (X_OK));
2071 if (NILP (path))
2072 return -1;
2073 if (posix_to_mac_pathname (SDATA (path), tempmacpathname,
2074 MAXPATHLEN+1) == 0)
2075 return -1;
2077 strcpy (macappname, tempmacpathname);
2079 else
2081 if (posix_to_mac_pathname (argv[0], macappname, MAXPATHLEN+1) == 0)
2082 return -1;
2084 newargv = (char **) alloca (sizeof (char *) * argc);
2085 newargc = argc;
2086 for (j = 1; j < argc; j++)
2088 if (strncmp (argv[j], "~emacs/", 7) == 0)
2090 char *t = strchr (argv[j], ' ');
2091 if (t)
2093 char tempcmdname[MAXPATHLEN+1], tempmaccmdname[MAXPATHLEN+1];
2094 strncpy (tempcmdname, argv[j], t-argv[j]);
2095 tempcmdname[t-argv[j]] = '\0';
2096 if (posix_to_mac_pathname (tempcmdname, tempmaccmdname,
2097 MAXPATHLEN+1) == 0)
2098 return -1;
2099 newargv[j] = (char *) alloca (strlen (tempmaccmdname)
2100 + strlen (t) + 1);
2101 strcpy (newargv[j], tempmaccmdname);
2102 strcat (newargv[j], t);
2104 else
2106 char tempmaccmdname[MAXPATHLEN+1];
2107 if (posix_to_mac_pathname (argv[j], tempmaccmdname,
2108 MAXPATHLEN+1) == 0)
2109 return -1;
2110 newargv[j] = (char *) alloca (strlen (tempmaccmdname)+1);
2111 strcpy (newargv[j], tempmaccmdname);
2114 else
2115 newargv[j] = argv[j];
2116 paramlen += strlen (newargv[j]) + 1;
2120 /* After expanding all the arguments, we now know the length of the
2121 parameter block to be sent to the subprocess as a message
2122 attached to the HLE. */
2123 param = (char *) malloc (paramlen + 1);
2124 if (!param)
2125 return -1;
2127 p = param;
2128 *p++ = newargc;
2129 /* first byte of message contains number of arguments for command */
2130 strcpy (p, macworkdir);
2131 p += strlen (macworkdir);
2132 *p++ = '\0';
2133 /* null terminate strings sent so it's possible to use strcpy over there */
2134 strcpy (p, macinfn);
2135 p += strlen (macinfn);
2136 *p++ = '\0';
2137 strcpy (p, macoutfn);
2138 p += strlen (macoutfn);
2139 *p++ = '\0';
2140 strcpy (p, macerrfn);
2141 p += strlen (macerrfn);
2142 *p++ = '\0';
2143 for (j = 1; j < newargc; j++)
2145 strcpy (p, newargv[j]);
2146 p += strlen (newargv[j]);
2147 *p++ = '\0';
2150 c2pstr (macappname);
2152 iErr = FSMakeFSSpec (0, 0, macappname, &spec);
2154 if (iErr != noErr)
2156 free (param);
2157 return -1;
2160 lpbr.launchBlockID = extendedBlock;
2161 lpbr.launchEPBLength = extendedBlockLen;
2162 lpbr.launchControlFlags = launchContinue + launchNoFileFlags;
2163 lpbr.launchAppSpec = &spec;
2164 lpbr.launchAppParameters = NULL;
2166 iErr = LaunchApplication (&lpbr); /* call the subprocess */
2167 if (iErr != noErr)
2169 free (param);
2170 return -1;
2173 send_event.what = kHighLevelEvent;
2174 send_event.message = kEmacsSubprocessSend;
2175 /* Event ID stored in "where" unused */
2177 retries = 3;
2178 /* OS may think current subprocess has terminated if previous one
2179 terminated recently. */
2182 iErr = PostHighLevelEvent (&send_event, &lpbr.launchProcessSN, 0, param,
2183 paramlen + 1, receiverIDisPSN);
2185 while (iErr == sessClosedErr && retries-- > 0);
2187 if (iErr != noErr)
2189 free (param);
2190 return -1;
2193 cursor_region_handle = NewRgn ();
2195 /* Wait for the subprocess to finish, when it will send us a ERPY
2196 high level event. */
2197 while (1)
2198 if (WaitNextEvent (highLevelEventMask, &reply_event, 180,
2199 cursor_region_handle)
2200 && reply_event.message == kEmacsSubprocessReply)
2201 break;
2203 /* The return code is sent through the refCon */
2204 iErr = AcceptHighLevelEvent (&targ, &ref_con, NULL, &len);
2205 if (iErr != noErr)
2207 DisposeHandle ((Handle) cursor_region_handle);
2208 free (param);
2209 return -1;
2212 DisposeHandle ((Handle) cursor_region_handle);
2213 free (param);
2215 return ref_con;
2216 #endif /* not TARGET_API_MAC_CARBON */
2220 DIR *
2221 opendir (const char *dirname)
2223 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
2224 char mac_pathname[MAXPATHLEN+1], vol_name[MAXPATHLEN+1];
2225 DIR *dirp;
2226 CInfoPBRec cipb;
2227 HVolumeParam vpb;
2228 int len, vol_name_len;
2230 if (find_true_pathname (dirname, true_pathname, MAXPATHLEN+1) == -1)
2231 return 0;
2233 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
2234 if (len > -1)
2235 fully_resolved_name[len] = '\0';
2236 else
2237 strcpy (fully_resolved_name, true_pathname);
2239 dirp = (DIR *) malloc (sizeof(DIR));
2240 if (!dirp)
2241 return 0;
2243 /* Handle special case when dirname is "/": sets up for readir to
2244 get all mount volumes. */
2245 if (strcmp (fully_resolved_name, "/") == 0)
2247 dirp->getting_volumes = 1; /* special all mounted volumes DIR struct */
2248 dirp->current_index = 1; /* index for first volume */
2249 return dirp;
2252 /* Handle typical cases: not accessing all mounted volumes. */
2253 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
2254 return 0;
2256 /* Emacs calls opendir without the trailing '/', Mac needs trailing ':' */
2257 len = strlen (mac_pathname);
2258 if (mac_pathname[len - 1] != ':' && len < MAXPATHLEN)
2259 strcat (mac_pathname, ":");
2261 /* Extract volume name */
2262 vol_name_len = strchr (mac_pathname, ':') - mac_pathname;
2263 strncpy (vol_name, mac_pathname, vol_name_len);
2264 vol_name[vol_name_len] = '\0';
2265 strcat (vol_name, ":");
2267 c2pstr (mac_pathname);
2268 cipb.hFileInfo.ioNamePtr = mac_pathname;
2269 /* using full pathname so vRefNum and DirID ignored */
2270 cipb.hFileInfo.ioVRefNum = 0;
2271 cipb.hFileInfo.ioDirID = 0;
2272 cipb.hFileInfo.ioFDirIndex = 0;
2273 /* set to 0 to get information about specific dir or file */
2275 errno = PBGetCatInfo (&cipb, false);
2276 if (errno != noErr)
2278 errno = ENOENT;
2279 return 0;
2282 if (!(cipb.hFileInfo.ioFlAttrib & 0x10)) /* bit 4 = 1 for directories */
2283 return 0; /* not a directory */
2285 dirp->dir_id = cipb.dirInfo.ioDrDirID; /* used later in readdir */
2286 dirp->getting_volumes = 0;
2287 dirp->current_index = 1; /* index for first file/directory */
2289 c2pstr (vol_name);
2290 vpb.ioNamePtr = vol_name;
2291 /* using full pathname so vRefNum and DirID ignored */
2292 vpb.ioVRefNum = 0;
2293 vpb.ioVolIndex = -1;
2294 errno = PBHGetVInfo ((union HParamBlockRec *) &vpb, false);
2295 if (errno != noErr)
2297 errno = ENOENT;
2298 return 0;
2301 dirp->vol_ref_num = vpb.ioVRefNum;
2303 return dirp;
2307 closedir (DIR *dp)
2309 free (dp);
2311 return 0;
2315 struct dirent *
2316 readdir (DIR *dp)
2318 HParamBlockRec hpblock;
2319 CInfoPBRec cipb;
2320 static struct dirent s_dirent;
2321 static Str255 s_name;
2322 int done;
2323 char *p;
2325 /* Handle the root directory containing the mounted volumes. Call
2326 PBHGetVInfo specifying an index to obtain the info for a volume.
2327 PBHGetVInfo returns an error when it receives an index beyond the
2328 last volume, at which time we should return a nil dirent struct
2329 pointer. */
2330 if (dp->getting_volumes)
2332 hpblock.volumeParam.ioNamePtr = s_name;
2333 hpblock.volumeParam.ioVRefNum = 0;
2334 hpblock.volumeParam.ioVolIndex = dp->current_index;
2336 errno = PBHGetVInfo (&hpblock, false);
2337 if (errno != noErr)
2339 errno = ENOENT;
2340 return 0;
2343 p2cstr (s_name);
2344 strcat (s_name, "/"); /* need "/" for stat to work correctly */
2346 dp->current_index++;
2348 s_dirent.d_ino = hpblock.volumeParam.ioVRefNum;
2349 s_dirent.d_name = s_name;
2351 return &s_dirent;
2353 else
2355 cipb.hFileInfo.ioVRefNum = dp->vol_ref_num;
2356 cipb.hFileInfo.ioNamePtr = s_name;
2357 /* location to receive filename returned */
2359 /* return only visible files */
2360 done = false;
2361 while (!done)
2363 cipb.hFileInfo.ioDirID = dp->dir_id;
2364 /* directory ID found by opendir */
2365 cipb.hFileInfo.ioFDirIndex = dp->current_index;
2367 errno = PBGetCatInfo (&cipb, false);
2368 if (errno != noErr)
2370 errno = ENOENT;
2371 return 0;
2374 /* insist on a visible entry */
2375 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* directory? */
2376 done = !(cipb.dirInfo.ioDrUsrWds.frFlags & fInvisible);
2377 else
2378 done = !(cipb.hFileInfo.ioFlFndrInfo.fdFlags & fInvisible);
2380 dp->current_index++;
2383 p2cstr (s_name);
2385 p = s_name;
2386 while (*p)
2388 if (*p == '/')
2389 *p = ':';
2390 p++;
2393 s_dirent.d_ino = cipb.dirInfo.ioDrDirID;
2394 /* value unimportant: non-zero for valid file */
2395 s_dirent.d_name = s_name;
2397 return &s_dirent;
2402 char *
2403 getwd (char *path)
2405 char mac_pathname[MAXPATHLEN+1];
2406 Str255 directory_name;
2407 OSErr errno;
2408 CInfoPBRec cipb;
2410 if (path_from_vol_dir_name (mac_pathname, 255, 0, 0, "\p") == 0)
2411 return NULL;
2413 if (mac_to_posix_pathname (mac_pathname, path, MAXPATHLEN+1) == 0)
2414 return 0;
2415 else
2416 return path;
2419 #endif /* ! MAC_OSX */
2422 void
2423 initialize_applescript ()
2425 AEDesc null_desc;
2426 OSAError osaerror;
2428 /* if open fails, as_scripting_component is set to NULL. Its
2429 subsequent use in OSA calls will fail with badComponentInstance
2430 error. */
2431 as_scripting_component = OpenDefaultComponent (kOSAComponentType,
2432 kAppleScriptSubtype);
2434 null_desc.descriptorType = typeNull;
2435 null_desc.dataHandle = 0;
2436 osaerror = OSAMakeContext (as_scripting_component, &null_desc,
2437 kOSANullScript, &as_script_context);
2438 if (osaerror)
2439 as_script_context = kOSANullScript;
2440 /* use default context if create fails */
2444 void terminate_applescript()
2446 OSADispose (as_scripting_component, as_script_context);
2447 CloseComponent (as_scripting_component);
2451 /* Compile and execute the AppleScript SCRIPT and return the error
2452 status as function value. A zero is returned if compilation and
2453 execution is successful, in which case RESULT returns a pointer to
2454 a string containing the resulting script value. Otherwise, the Mac
2455 error code is returned and RESULT returns a pointer to an error
2456 string. In both cases the caller should deallocate the storage
2457 used by the string pointed to by RESULT if it is non-NULL. For
2458 documentation on the MacOS scripting architecture, see Inside
2459 Macintosh - Interapplication Communications: Scripting Components. */
2461 static long
2462 do_applescript (char *script, char **result)
2464 AEDesc script_desc, result_desc, error_desc;
2465 OSErr error;
2466 OSAError osaerror;
2467 long length;
2469 *result = 0;
2471 if (!as_scripting_component)
2472 initialize_applescript();
2474 error = AECreateDesc (typeChar, script, strlen(script), &script_desc);
2475 if (error)
2476 return error;
2478 osaerror = OSADoScript (as_scripting_component, &script_desc, kOSANullScript,
2479 typeChar, kOSAModeNull, &result_desc);
2481 if (osaerror == errOSAScriptError)
2483 /* error executing AppleScript: retrieve error message */
2484 if (!OSAScriptError (as_scripting_component, kOSAErrorMessage, typeChar,
2485 &error_desc))
2487 #if TARGET_API_MAC_CARBON
2488 length = AEGetDescDataSize (&error_desc);
2489 *result = (char *) xmalloc (length + 1);
2490 if (*result)
2492 AEGetDescData (&error_desc, *result, length);
2493 *(*result + length) = '\0';
2495 #else /* not TARGET_API_MAC_CARBON */
2496 HLock (error_desc.dataHandle);
2497 length = GetHandleSize(error_desc.dataHandle);
2498 *result = (char *) xmalloc (length + 1);
2499 if (*result)
2501 memcpy (*result, *(error_desc.dataHandle), length);
2502 *(*result + length) = '\0';
2504 HUnlock (error_desc.dataHandle);
2505 #endif /* not TARGET_API_MAC_CARBON */
2506 AEDisposeDesc (&error_desc);
2509 else if (osaerror == noErr) /* success: retrieve resulting script value */
2511 #if TARGET_API_MAC_CARBON
2512 length = AEGetDescDataSize (&result_desc);
2513 *result = (char *) xmalloc (length + 1);
2514 if (*result)
2516 AEGetDescData (&result_desc, *result, length);
2517 *(*result + length) = '\0';
2519 #else /* not TARGET_API_MAC_CARBON */
2520 HLock (result_desc.dataHandle);
2521 length = GetHandleSize(result_desc.dataHandle);
2522 *result = (char *) xmalloc (length + 1);
2523 if (*result)
2525 memcpy (*result, *(result_desc.dataHandle), length);
2526 *(*result + length) = '\0';
2528 HUnlock (result_desc.dataHandle);
2529 #endif /* not TARGET_API_MAC_CARBON */
2530 AEDisposeDesc (&result_desc);
2533 AEDisposeDesc (&script_desc);
2535 return osaerror;
2539 DEFUN ("do-applescript", Fdo_applescript, Sdo_applescript, 1, 1, 0,
2540 doc: /* Compile and execute AppleScript SCRIPT and retrieve and return the result.
2541 If compilation and execution are successful, the resulting script
2542 value is returned as a string. Otherwise the function aborts and
2543 displays the error message returned by the AppleScript scripting
2544 component. */)
2545 (script)
2546 Lisp_Object script;
2548 char *result, *temp;
2549 Lisp_Object lisp_result;
2550 long status;
2552 CHECK_STRING (script);
2554 BLOCK_INPUT;
2555 status = do_applescript (SDATA (script), &result);
2556 UNBLOCK_INPUT;
2557 if (status)
2559 if (!result)
2560 error ("AppleScript error %d", status);
2561 else
2563 /* Unfortunately only OSADoScript in do_applescript knows how
2564 how large the resulting script value or error message is
2565 going to be and therefore as caller memory must be
2566 deallocated here. It is necessary to free the error
2567 message before calling error to avoid a memory leak. */
2568 temp = (char *) alloca (strlen (result) + 1);
2569 strcpy (temp, result);
2570 xfree (result);
2571 error (temp);
2574 else
2576 lisp_result = build_string (result);
2577 xfree (result);
2578 return lisp_result;
2583 DEFUN ("mac-file-name-to-posix", Fmac_file_name_to_posix,
2584 Smac_file_name_to_posix, 1, 1, 0,
2585 doc: /* Convert Macintosh filename to Posix form. */)
2586 (mac_filename)
2587 Lisp_Object mac_filename;
2589 char posix_filename[MAXPATHLEN+1];
2591 CHECK_STRING (mac_filename);
2593 if (mac_to_posix_pathname (SDATA (mac_filename), posix_filename,
2594 MAXPATHLEN))
2595 return build_string (posix_filename);
2596 else
2597 return Qnil;
2601 DEFUN ("posix-file-name-to-mac", Fposix_file_name_to_mac,
2602 Sposix_file_name_to_mac, 1, 1, 0,
2603 doc: /* Convert Posix filename to Mac form. */)
2604 (posix_filename)
2605 Lisp_Object posix_filename;
2607 char mac_filename[MAXPATHLEN+1];
2609 CHECK_STRING (posix_filename);
2611 if (posix_to_mac_pathname (SDATA (posix_filename), mac_filename,
2612 MAXPATHLEN))
2613 return build_string (mac_filename);
2614 else
2615 return Qnil;
2619 /* set interprogram-paste-function to mac-paste-function in mac-win.el
2620 to enable Emacs to obtain the contents of the Mac clipboard. */
2621 DEFUN ("mac-paste-function", Fmac_paste_function, Smac_paste_function, 0, 0, 0,
2622 doc: /* Return the contents of the Mac clipboard as a string. */)
2625 #if TARGET_API_MAC_CARBON
2626 OSStatus err;
2627 ScrapRef scrap;
2628 ScrapFlavorFlags sff;
2629 Size s;
2630 int i;
2631 char *data;
2633 BLOCK_INPUT;
2634 err = GetCurrentScrap (&scrap);
2635 if (err == noErr)
2636 err = GetScrapFlavorFlags (scrap, kScrapFlavorTypeText, &sff);
2637 if (err == noErr)
2638 err = GetScrapFlavorSize (scrap, kScrapFlavorTypeText, &s);
2639 if (err == noErr && (data = (char*) alloca (s)))
2640 err = GetScrapFlavorData (scrap, kScrapFlavorTypeText, &s, data);
2641 UNBLOCK_INPUT;
2642 if (err != noErr || s == 0)
2643 return Qnil;
2645 /* Emacs expects clipboard contents have Unix-style eol's */
2646 for (i = 0; i < s; i++)
2647 if (data[i] == '\r')
2648 data[i] = '\n';
2650 return make_string (data, s);
2651 #else /* not TARGET_API_MAC_CARBON */
2652 Lisp_Object value;
2653 Handle my_handle;
2654 long scrap_offset, rc, i;
2656 my_handle = NewHandle (0); /* allocate 0-length data area */
2658 rc = GetScrap (my_handle, 'TEXT', &scrap_offset);
2659 if (rc < 0)
2660 return Qnil;
2662 HLock (my_handle);
2664 /* Emacs expects clipboard contents have Unix-style eol's */
2665 for (i = 0; i < rc; i++)
2666 if ((*my_handle)[i] == '\r')
2667 (*my_handle)[i] = '\n';
2669 value = make_string (*my_handle, rc);
2671 HUnlock (my_handle);
2673 DisposeHandle (my_handle);
2675 return value;
2676 #endif /* not TARGET_API_MAC_CARBON */
2680 /* set interprogram-cut-function to mac-cut-function in mac-win.el
2681 to enable Emacs to write the top of the kill-ring to the Mac clipboard. */
2682 DEFUN ("mac-cut-function", Fmac_cut_function, Smac_cut_function, 1, 2, 0,
2683 doc: /* Put the value of the string parameter to the Mac clipboard. */)
2684 (value, push)
2685 Lisp_Object value, push;
2687 char *buf;
2688 int len, i;
2690 /* fixme: ignore the push flag for now */
2692 CHECK_STRING (value);
2694 len = SCHARS (value);
2695 buf = (char *) alloca (len+1);
2696 bcopy (SDATA (value), buf, len);
2697 buf[len] = '\0';
2699 /* convert to Mac-style eol's before sending to clipboard */
2700 for (i = 0; i < len; i++)
2701 if (buf[i] == '\n')
2702 buf[i] = '\r';
2704 #if TARGET_API_MAC_CARBON
2706 ScrapRef scrap;
2708 BLOCK_INPUT;
2709 ClearCurrentScrap ();
2710 if (GetCurrentScrap (&scrap) != noErr)
2712 UNBLOCK_INPUT;
2713 error ("cannot get current scrap");
2716 if (PutScrapFlavor (scrap, kScrapFlavorTypeText, kScrapFlavorMaskNone, len,
2717 buf) != noErr)
2719 UNBLOCK_INPUT;
2720 error ("cannot put to scrap");
2722 UNBLOCK_INPUT;
2724 #else /* not TARGET_API_MAC_CARBON */
2725 ZeroScrap ();
2726 PutScrap (len, 'TEXT', buf);
2727 #endif /* not TARGET_API_MAC_CARBON */
2729 return Qnil;
2733 DEFUN ("x-selection-exists-p", Fx_selection_exists_p, Sx_selection_exists_p,
2734 0, 1, 0,
2735 doc: /* Whether there is an owner for the given X Selection.
2736 The arg should be the name of the selection in question, typically one of
2737 the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.
2738 \(Those are literal upper-case symbol names, since that's what X expects.)
2739 For convenience, the symbol nil is the same as `PRIMARY',
2740 and t is the same as `SECONDARY'. */)
2741 (selection)
2742 Lisp_Object selection;
2744 CHECK_SYMBOL (selection);
2746 /* Return nil for PRIMARY and SECONDARY selections; for CLIPBOARD, check
2747 if the clipboard currently has valid text format contents. */
2749 if (EQ (selection, QCLIPBOARD))
2751 Lisp_Object val = Qnil;
2753 #if TARGET_API_MAC_CARBON
2754 ScrapRef scrap;
2755 ScrapFlavorFlags sff;
2757 BLOCK_INPUT;
2758 if (GetCurrentScrap (&scrap) == noErr)
2759 if (GetScrapFlavorFlags (scrap, kScrapFlavorTypeText, &sff) == noErr)
2760 val = Qt;
2761 UNBLOCK_INPUT;
2762 #else /* not TARGET_API_MAC_CARBON */
2763 Handle my_handle;
2764 long rc, scrap_offset;
2766 my_handle = NewHandle (0);
2768 rc = GetScrap (my_handle, 'TEXT', &scrap_offset);
2769 if (rc >= 0)
2770 val = Qt;
2772 DisposeHandle (my_handle);
2773 #endif /* not TARGET_API_MAC_CARBON */
2775 return val;
2777 return Qnil;
2780 #ifdef MAC_OSX
2781 #undef select
2783 extern int inhibit_window_system;
2784 extern int noninteractive;
2786 /* When Emacs is started from the Finder, SELECT always immediately
2787 returns as if input is present when file descriptor 0 is polled for
2788 input. Strangely, when Emacs is run as a GUI application from the
2789 command line, it blocks in the same situation. This `wrapper' of
2790 the system call SELECT corrects this discrepancy. */
2792 sys_select (n, rfds, wfds, efds, timeout)
2793 int n;
2794 SELECT_TYPE *rfds;
2795 SELECT_TYPE *wfds;
2796 SELECT_TYPE *efds;
2797 struct timeval *timeout;
2799 OSErr err;
2800 EMACS_TIME end_time, now, remaining_time;
2802 if (inhibit_window_system || noninteractive
2803 || rfds == NULL || !FD_ISSET (0, rfds))
2804 return select (n, rfds, wfds, efds, timeout);
2806 if (wfds == NULL && efds == NULL)
2808 int i;
2810 for (i = 1; i < n; i++)
2811 if (FD_ISSET (i, rfds))
2812 break;
2813 if (i == n)
2815 EventTimeout timeout_sec =
2816 (timeout
2817 ? (EMACS_SECS (*timeout) * kEventDurationSecond
2818 + EMACS_USECS (*timeout) * kEventDurationMicrosecond)
2819 : kEventDurationForever);
2821 BLOCK_INPUT;
2822 err = ReceiveNextEvent (0, NULL, timeout_sec,
2823 kEventLeaveInQueue, NULL);
2824 UNBLOCK_INPUT;
2825 if (err == noErr)
2827 FD_ZERO (rfds);
2828 FD_SET (0, rfds);
2829 return 1;
2831 else
2832 return 0;
2836 if (timeout)
2838 remaining_time = *timeout;
2839 EMACS_GET_TIME (now);
2840 EMACS_ADD_TIME (end_time, now, remaining_time);
2842 FD_CLR (0, rfds);
2845 EMACS_TIME select_timeout;
2846 SELECT_TYPE orfds = *rfds;
2847 int r;
2849 EMACS_SET_SECS_USECS (select_timeout, 0, 20000);
2851 if (timeout && EMACS_TIME_LT (remaining_time, select_timeout))
2852 select_timeout = remaining_time;
2854 r = select (n, &orfds, wfds, efds, &select_timeout);
2855 BLOCK_INPUT;
2856 err = ReceiveNextEvent (0, NULL, kEventDurationNoWait,
2857 kEventLeaveInQueue, NULL);
2858 UNBLOCK_INPUT;
2859 if (r > 0)
2861 *rfds = orfds;
2862 if (err == noErr)
2864 FD_SET (0, rfds);
2865 r++;
2867 return r;
2869 else if (err == noErr)
2871 FD_ZERO (rfds);
2872 FD_SET (0, rfds);
2873 return 1;
2876 if (timeout)
2878 EMACS_GET_TIME (now);
2879 EMACS_SUB_TIME (remaining_time, end_time, now);
2882 while (!timeout || EMACS_TIME_LT (now, end_time));
2884 return 0;
2887 /* Set up environment variables so that Emacs can correctly find its
2888 support files when packaged as an application bundle. Directories
2889 placed in /usr/local/share/emacs/<emacs-version>/, /usr/local/bin,
2890 and /usr/local/libexec/emacs/<emacs-version>/<system-configuration>
2891 by `make install' by default can instead be placed in
2892 .../Emacs.app/Contents/Resources/ and
2893 .../Emacs.app/Contents/MacOS/. Each of these environment variables
2894 is changed only if it is not already set. Presumably if the user
2895 sets an environment variable, he will want to use files in his path
2896 instead of ones in the application bundle. */
2897 void
2898 init_mac_osx_environment ()
2900 CFBundleRef bundle;
2901 CFURLRef bundleURL;
2902 CFStringRef cf_app_bundle_pathname;
2903 int app_bundle_pathname_len;
2904 char *app_bundle_pathname;
2905 char *p, *q;
2906 struct stat st;
2908 /* Fetch the pathname of the application bundle as a C string into
2909 app_bundle_pathname. */
2911 bundle = CFBundleGetMainBundle ();
2912 if (!bundle)
2913 return;
2915 bundleURL = CFBundleCopyBundleURL (bundle);
2916 if (!bundleURL)
2917 return;
2919 cf_app_bundle_pathname = CFURLCopyFileSystemPath (bundleURL,
2920 kCFURLPOSIXPathStyle);
2921 app_bundle_pathname_len = CFStringGetLength (cf_app_bundle_pathname);
2922 app_bundle_pathname = (char *) alloca (app_bundle_pathname_len + 1);
2924 if (!CFStringGetCString (cf_app_bundle_pathname,
2925 app_bundle_pathname,
2926 app_bundle_pathname_len + 1,
2927 kCFStringEncodingISOLatin1))
2929 CFRelease (cf_app_bundle_pathname);
2930 return;
2933 CFRelease (cf_app_bundle_pathname);
2935 /* P should have sufficient room for the pathname of the bundle plus
2936 the subpath in it leading to the respective directories. Q
2937 should have three times that much room because EMACSLOADPATH can
2938 have the value "<path to lisp dir>:<path to leim dir>:<path to
2939 site-lisp dir>". */
2940 p = (char *) alloca (app_bundle_pathname_len + 50);
2941 q = (char *) alloca (3 * app_bundle_pathname_len + 150);
2942 if (!getenv ("EMACSLOADPATH"))
2944 q[0] = '\0';
2946 strcpy (p, app_bundle_pathname);
2947 strcat (p, "/Contents/Resources/lisp");
2948 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
2949 strcat (q, p);
2951 strcpy (p, app_bundle_pathname);
2952 strcat (p, "/Contents/Resources/leim");
2953 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
2955 if (q[0] != '\0')
2956 strcat (q, ":");
2957 strcat (q, p);
2960 strcpy (p, app_bundle_pathname);
2961 strcat (p, "/Contents/Resources/site-lisp");
2962 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
2964 if (q[0] != '\0')
2965 strcat (q, ":");
2966 strcat (q, p);
2969 if (q[0] != '\0')
2970 setenv ("EMACSLOADPATH", q, 1);
2973 if (!getenv ("EMACSPATH"))
2975 q[0] = '\0';
2977 strcpy (p, app_bundle_pathname);
2978 strcat (p, "/Contents/MacOS/libexec");
2979 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
2980 strcat (q, p);
2982 strcpy (p, app_bundle_pathname);
2983 strcat (p, "/Contents/MacOS/bin");
2984 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
2986 if (q[0] != '\0')
2987 strcat (q, ":");
2988 strcat (q, p);
2991 if (q[0] != '\0')
2992 setenv ("EMACSPATH", q, 1);
2995 if (!getenv ("EMACSDATA"))
2997 strcpy (p, app_bundle_pathname);
2998 strcat (p, "/Contents/Resources/etc");
2999 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
3000 setenv ("EMACSDATA", p, 1);
3003 if (!getenv ("EMACSDOC"))
3005 strcpy (p, app_bundle_pathname);
3006 strcat (p, "/Contents/Resources/etc");
3007 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
3008 setenv ("EMACSDOC", p, 1);
3011 if (!getenv ("INFOPATH"))
3013 strcpy (p, app_bundle_pathname);
3014 strcat (p, "/Contents/Resources/info");
3015 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
3016 setenv ("INFOPATH", p, 1);
3019 #endif /* MAC_OSX */
3021 void
3022 syms_of_mac ()
3024 QCLIPBOARD = intern ("CLIPBOARD");
3025 staticpro (&QCLIPBOARD);
3027 defsubr (&Smac_paste_function);
3028 defsubr (&Smac_cut_function);
3029 defsubr (&Sx_selection_exists_p);
3031 defsubr (&Sdo_applescript);
3032 defsubr (&Smac_file_name_to_posix);
3033 defsubr (&Sposix_file_name_to_mac);
3036 /* arch-tag: 29d30c1f-0c6b-4f88-8a6d-0558d7f9dbff
3037 (do not change this comment) */