(cpp-choose-symbol): Don't cons unnecessarily.
[emacs.git] / src / mac.c
blobadf1dff315777cb9657a1d293349154c3af8311b
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/stat.h>
30 #include <string.h>
31 #include <pwd.h>
32 #include <sys/param.h>
33 #if __MWERKS__
34 #include <unistd.h>
35 #endif
37 #ifdef MAC_OSX
38 #undef mktime
39 #undef DEBUG
40 #undef free
41 #undef malloc
42 #undef realloc
43 #include <Carbon/Carbon.h>
44 #undef free
45 #define free unexec_free
46 #undef malloc
47 #define malloc unexec_malloc
48 #undef realloc
49 #define realloc unexec_realloc
50 #else /* not MAC_OSX */
51 #include <Files.h>
52 #include <MacTypes.h>
53 #include <TextUtils.h>
54 #include <Folders.h>
55 #include <Resources.h>
56 #include <Aliases.h>
57 #include <FixMath.h>
58 #include <Timer.h>
59 #include <OSA.h>
60 #include <AppleScript.h>
61 #include <Scrap.h>
62 #endif /* not MAC_OSX */
64 #include "lisp.h"
65 #include "process.h"
66 #include "sysselect.h"
67 #include "systime.h"
69 Lisp_Object QCLIPBOARD;
71 /* An instance of the AppleScript component. */
72 static ComponentInstance as_scripting_component;
73 /* The single script context used for all script executions. */
74 static OSAID as_script_context;
77 /* When converting from Mac to Unix pathnames, /'s in folder names are
78 converted to :'s. This function, used in copying folder names,
79 performs a strncat and converts all character a to b in the copy of
80 the string s2 appended to the end of s1. */
82 void
83 string_cat_and_replace (char *s1, const char *s2, int n, char a, char b)
85 int l1 = strlen (s1);
86 int l2 = strlen (s2);
87 char *p = s1 + l1;
88 int i;
90 strncat (s1, s2, n);
91 for (i = 0; i < l2; i++)
93 if (*p == a)
94 *p = b;
95 p++;
100 /* Convert a Mac pathname to Posix form. A Mac full pathname is one
101 that does not begin with a ':' and contains at least one ':'. A Mac
102 full pathname causes an '/' to be prepended to the Posix pathname.
103 The algorithm for the rest of the pathname is as follows:
104 For each segment between two ':',
105 if it is non-null, copy as is and then add a '/' at the end,
106 otherwise, insert a "../" into the Posix pathname.
107 Returns 1 if successful; 0 if fails. */
110 mac_to_posix_pathname (const char *mfn, char *ufn, int ufnbuflen)
112 const char *p, *q, *pe;
114 strcpy (ufn, "");
116 if (*mfn == '\0')
117 return 1;
119 p = strchr (mfn, ':');
120 if (p != 0 && p != mfn) /* full pathname */
121 strcat (ufn, "/");
123 p = mfn;
124 if (*p == ':')
125 p++;
127 pe = mfn + strlen (mfn);
128 while (p < pe)
130 q = strchr (p, ':');
131 if (q)
133 if (q == p)
134 { /* two consecutive ':' */
135 if (strlen (ufn) + 3 >= ufnbuflen)
136 return 0;
137 strcat (ufn, "../");
139 else
141 if (strlen (ufn) + (q - p) + 1 >= ufnbuflen)
142 return 0;
143 string_cat_and_replace (ufn, p, q - p, '/', ':');
144 strcat (ufn, "/");
146 p = q + 1;
148 else
150 if (strlen (ufn) + (pe - p) >= ufnbuflen)
151 return 0;
152 string_cat_and_replace (ufn, p, pe - p, '/', ':');
153 /* no separator for last one */
154 p = pe;
158 return 1;
162 extern char *get_temp_dir_name ();
165 /* Convert a Posix pathname to Mac form. Approximately reverse of the
166 above in algorithm. */
169 posix_to_mac_pathname (const char *ufn, char *mfn, int mfnbuflen)
171 const char *p, *q, *pe;
172 char expanded_pathname[MAXPATHLEN+1];
174 strcpy (mfn, "");
176 if (*ufn == '\0')
177 return 1;
179 p = ufn;
181 /* Check for and handle volume names. Last comparison: strangely
182 somewhere "/.emacs" is passed. A temporary fix for now. */
183 if (*p == '/' && strchr (p+1, '/') == NULL && strcmp (p, "/.emacs") != 0)
185 if (strlen (p) + 1 > mfnbuflen)
186 return 0;
187 strcpy (mfn, p+1);
188 strcat (mfn, ":");
189 return 1;
192 /* expand to emacs dir found by init_emacs_passwd_dir */
193 if (strncmp (p, "~emacs/", 7) == 0)
195 struct passwd *pw = getpwnam ("emacs");
196 p += 7;
197 if (strlen (pw->pw_dir) + strlen (p) > MAXPATHLEN)
198 return 0;
199 strcpy (expanded_pathname, pw->pw_dir);
200 strcat (expanded_pathname, p);
201 p = expanded_pathname;
202 /* now p points to the pathname with emacs dir prefix */
204 else if (strncmp (p, "/tmp/", 5) == 0)
206 char *t = get_temp_dir_name ();
207 p += 5;
208 if (strlen (t) + strlen (p) > MAXPATHLEN)
209 return 0;
210 strcpy (expanded_pathname, t);
211 strcat (expanded_pathname, p);
212 p = expanded_pathname;
213 /* now p points to the pathname with emacs dir prefix */
215 else if (*p != '/') /* relative pathname */
216 strcat (mfn, ":");
218 if (*p == '/')
219 p++;
221 pe = p + strlen (p);
222 while (p < pe)
224 q = strchr (p, '/');
225 if (q)
227 if (q - p == 2 && *p == '.' && *(p+1) == '.')
229 if (strlen (mfn) + 1 >= mfnbuflen)
230 return 0;
231 strcat (mfn, ":");
233 else
235 if (strlen (mfn) + (q - p) + 1 >= mfnbuflen)
236 return 0;
237 string_cat_and_replace (mfn, p, q - p, ':', '/');
238 strcat (mfn, ":");
240 p = q + 1;
242 else
244 if (strlen (mfn) + (pe - p) >= mfnbuflen)
245 return 0;
246 string_cat_and_replace (mfn, p, pe - p, ':', '/');
247 p = pe;
251 return 1;
254 #ifndef MAC_OSX
256 /* The following functions with "sys_" prefix are stubs to Unix
257 functions that have already been implemented by CW or MPW. The
258 calls to them in Emacs source course are #define'd to call the sys_
259 versions by the header files s-mac.h. In these stubs pathnames are
260 converted between their Unix and Mac forms. */
263 /* Unix epoch is Jan 1, 1970 while Mac epoch is Jan 1, 1904: 66 years
264 + 17 leap days. These are for adjusting time values returned by
265 MacOS Toolbox functions. */
267 #define MAC_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
269 #ifdef __MWERKS__
270 #if __MSL__ < 0x6000
271 /* CW Pro 5 epoch is Jan 1, 1900 (aaarghhhhh!); remember, 1900 is not
272 a leap year! This is for adjusting time_t values returned by MSL
273 functions. */
274 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 70 + 17) * 24 * 60 * 60)
275 #else /* __MSL__ >= 0x6000 */
276 /* CW changes Pro 6 to follow Unix! */
277 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
278 #endif /* __MSL__ >= 0x6000 */
279 #elif __MRC__
280 /* MPW library functions follow Unix (confused?). */
281 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
282 #else /* not __MRC__ */
283 You lose!!!
284 #endif /* not __MRC__ */
287 /* Define our own stat function for both MrC and CW. The reason for
288 doing this: "stat" is both the name of a struct and function name:
289 can't use the same trick like that for sys_open, sys_close, etc. to
290 redirect Emacs's calls to our own version that converts Unix style
291 filenames to Mac style filename because all sorts of compilation
292 errors will be generated if stat is #define'd to be sys_stat. */
295 stat_noalias (const char *path, struct stat *buf)
297 char mac_pathname[MAXPATHLEN+1];
298 CInfoPBRec cipb;
300 if (posix_to_mac_pathname (path, mac_pathname, MAXPATHLEN+1) == 0)
301 return -1;
303 c2pstr (mac_pathname);
304 cipb.hFileInfo.ioNamePtr = mac_pathname;
305 cipb.hFileInfo.ioVRefNum = 0;
306 cipb.hFileInfo.ioDirID = 0;
307 cipb.hFileInfo.ioFDirIndex = 0;
308 /* set to 0 to get information about specific dir or file */
310 errno = PBGetCatInfo (&cipb, false);
311 if (errno == -43) /* -43: fnfErr defined in Errors.h */
312 errno = ENOENT;
313 if (errno != noErr)
314 return -1;
316 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* bit 4 = 1 for directories */
318 buf->st_mode = S_IFDIR | S_IREAD | S_IEXEC;
320 if (!(cipb.hFileInfo.ioFlAttrib & 0x1))
321 buf->st_mode |= S_IWRITE; /* bit 1 = 1 for locked files/directories */
322 buf->st_ino = cipb.dirInfo.ioDrDirID;
323 buf->st_dev = cipb.dirInfo.ioVRefNum;
324 buf->st_size = cipb.dirInfo.ioDrNmFls;
325 /* size of dir = number of files and dirs */
326 buf->st_atime
327 = buf->st_mtime
328 = cipb.dirInfo.ioDrMdDat - MAC_UNIX_EPOCH_DIFF;
329 buf->st_ctime = cipb.dirInfo.ioDrCrDat - MAC_UNIX_EPOCH_DIFF;
331 else
333 buf->st_mode = S_IFREG | S_IREAD;
334 if (!(cipb.hFileInfo.ioFlAttrib & 0x1))
335 buf->st_mode |= S_IWRITE; /* bit 1 = 1 for locked files/directories */
336 if (cipb.hFileInfo.ioFlFndrInfo.fdType == 'APPL')
337 buf->st_mode |= S_IEXEC;
338 buf->st_ino = cipb.hFileInfo.ioDirID;
339 buf->st_dev = cipb.hFileInfo.ioVRefNum;
340 buf->st_size = cipb.hFileInfo.ioFlLgLen;
341 buf->st_atime
342 = buf->st_mtime
343 = cipb.hFileInfo.ioFlMdDat - MAC_UNIX_EPOCH_DIFF;
344 buf->st_ctime = cipb.hFileInfo.ioFlCrDat - MAC_UNIX_EPOCH_DIFF;
347 if (cipb.hFileInfo.ioFlFndrInfo.fdFlags & 0x8000)
349 /* identify alias files as symlinks */
350 buf->st_mode &= ~S_IFREG;
351 buf->st_mode |= S_IFLNK;
354 buf->st_nlink = 1;
355 buf->st_uid = getuid ();
356 buf->st_gid = getgid ();
357 buf->st_rdev = 0;
359 return 0;
364 lstat (const char *path, struct stat *buf)
366 int result;
367 char true_pathname[MAXPATHLEN+1];
369 /* Try looking for the file without resolving aliases first. */
370 if ((result = stat_noalias (path, buf)) >= 0)
371 return result;
373 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
374 return -1;
376 return stat_noalias (true_pathname, buf);
381 stat (const char *path, struct stat *sb)
383 int result;
384 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
385 int len;
387 if ((result = stat_noalias (path, sb)) >= 0 &&
388 ! (sb->st_mode & S_IFLNK))
389 return result;
391 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
392 return -1;
394 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
395 if (len > -1)
397 fully_resolved_name[len] = '\0';
398 /* in fact our readlink terminates strings */
399 return lstat (fully_resolved_name, sb);
401 else
402 return lstat (true_pathname, sb);
406 #if __MRC__
407 /* CW defines fstat in stat.mac.c while MPW does not provide this
408 function. Without the information of how to get from a file
409 descriptor in MPW StdCLib to a Mac OS file spec, it should be hard
410 to implement this function. Fortunately, there is only one place
411 where this function is called in our configuration: in fileio.c,
412 where only the st_dev and st_ino fields are used to determine
413 whether two fildes point to different i-nodes to prevent copying
414 a file onto itself equal. What we have here probably needs
415 improvement. */
418 fstat (int fildes, struct stat *buf)
420 buf->st_dev = 0;
421 buf->st_ino = fildes;
422 buf->st_mode = S_IFREG; /* added by T.I. for the copy-file */
423 return 0; /* success */
425 #endif /* __MRC__ */
429 mkdir (const char *dirname, int mode)
431 #pragma unused(mode)
433 HFileParam hfpb;
434 char true_pathname[MAXPATHLEN+1], mac_pathname[MAXPATHLEN+1];
436 if (find_true_pathname (dirname, true_pathname, MAXPATHLEN+1) == -1)
437 return -1;
439 if (posix_to_mac_pathname (true_pathname, mac_pathname, MAXPATHLEN+1) == 0)
440 return -1;
442 c2pstr (mac_pathname);
443 hfpb.ioNamePtr = mac_pathname;
444 hfpb.ioVRefNum = 0; /* ignored unless name is invalid */
445 hfpb.ioDirID = 0; /* parent is the root */
447 errno = PBDirCreate ((HParmBlkPtr) &hfpb, false);
448 /* just return the Mac OSErr code for now */
449 return errno == noErr ? 0 : -1;
453 #undef rmdir
454 sys_rmdir (const char *dirname)
456 HFileParam hfpb;
457 char mac_pathname[MAXPATHLEN+1];
459 if (posix_to_mac_pathname (dirname, mac_pathname, MAXPATHLEN+1) == 0)
460 return -1;
462 c2pstr (mac_pathname);
463 hfpb.ioNamePtr = mac_pathname;
464 hfpb.ioVRefNum = 0; /* ignored unless name is invalid */
465 hfpb.ioDirID = 0; /* parent is the root */
467 errno = PBHDelete ((HParmBlkPtr) &hfpb, false);
468 return errno == noErr ? 0 : -1;
472 #ifdef __MRC__
473 /* No implementation yet. */
475 execvp (const char *path, ...)
477 return -1;
479 #endif /* __MRC__ */
483 utime (const char *path, const struct utimbuf *times)
485 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
486 int len;
487 char mac_pathname[MAXPATHLEN+1];
488 CInfoPBRec cipb;
490 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
491 return -1;
493 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
494 if (len > -1)
495 fully_resolved_name[len] = '\0';
496 else
497 strcpy (fully_resolved_name, true_pathname);
499 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
500 return -1;
502 c2pstr (mac_pathname);
503 cipb.hFileInfo.ioNamePtr = mac_pathname;
504 cipb.hFileInfo.ioVRefNum = 0;
505 cipb.hFileInfo.ioDirID = 0;
506 cipb.hFileInfo.ioFDirIndex = 0;
507 /* set to 0 to get information about specific dir or file */
509 errno = PBGetCatInfo (&cipb, false);
510 if (errno != noErr)
511 return -1;
513 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* bit 4 = 1 for directories */
515 if (times)
516 cipb.dirInfo.ioDrMdDat = times->modtime + MAC_UNIX_EPOCH_DIFF;
517 else
518 GetDateTime (&cipb.dirInfo.ioDrMdDat);
520 else
522 if (times)
523 cipb.hFileInfo.ioFlMdDat = times->modtime + MAC_UNIX_EPOCH_DIFF;
524 else
525 GetDateTime (&cipb.hFileInfo.ioFlMdDat);
528 errno = PBSetCatInfo (&cipb, false);
529 return errno == noErr ? 0 : -1;
533 #ifndef F_OK
534 #define F_OK 0
535 #endif
536 #ifndef X_OK
537 #define X_OK 1
538 #endif
539 #ifndef W_OK
540 #define W_OK 2
541 #endif
543 /* Like stat, but test for access mode in hfpb.ioFlAttrib */
545 access (const char *path, int mode)
547 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
548 int len;
549 char mac_pathname[MAXPATHLEN+1];
550 CInfoPBRec cipb;
552 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
553 return -1;
555 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
556 if (len > -1)
557 fully_resolved_name[len] = '\0';
558 else
559 strcpy (fully_resolved_name, true_pathname);
561 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
562 return -1;
564 c2pstr (mac_pathname);
565 cipb.hFileInfo.ioNamePtr = mac_pathname;
566 cipb.hFileInfo.ioVRefNum = 0;
567 cipb.hFileInfo.ioDirID = 0;
568 cipb.hFileInfo.ioFDirIndex = 0;
569 /* set to 0 to get information about specific dir or file */
571 errno = PBGetCatInfo (&cipb, false);
572 if (errno != noErr)
573 return -1;
575 if (mode == F_OK) /* got this far, file exists */
576 return 0;
578 if (mode & X_OK)
579 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* path refers to a directory */
580 return 0;
581 else
583 if (cipb.hFileInfo.ioFlFndrInfo.fdType == 'APPL')
584 return 0;
585 else
586 return -1;
589 if (mode & W_OK)
590 return (cipb.hFileInfo.ioFlAttrib & 0x1) ? -1 : 0;
591 /* don't allow if lock bit is on */
593 return -1;
597 #define DEV_NULL_FD 0x10000
599 #undef open
601 sys_open (const char *path, int oflag)
603 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
604 int len;
605 char mac_pathname[MAXPATHLEN+1];
607 if (strcmp (path, "/dev/null") == 0)
608 return DEV_NULL_FD; /* some bogus fd to be ignored in write */
610 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
611 return -1;
613 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
614 if (len > -1)
615 fully_resolved_name[len] = '\0';
616 else
617 strcpy (fully_resolved_name, true_pathname);
619 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
620 return -1;
621 else
623 #ifdef __MRC__
624 int res = open (mac_pathname, oflag);
625 /* if (oflag == O_WRONLY || oflag == O_RDWR) */
626 if (oflag & O_CREAT)
627 fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
628 return res;
629 #else /* not __MRC__ */
630 return open (mac_pathname, oflag);
631 #endif /* not __MRC__ */
636 #undef creat
638 sys_creat (const char *path, mode_t mode)
640 char true_pathname[MAXPATHLEN+1];
641 int len;
642 char mac_pathname[MAXPATHLEN+1];
644 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
645 return -1;
647 if (!posix_to_mac_pathname (true_pathname, mac_pathname, MAXPATHLEN+1))
648 return -1;
649 else
651 #ifdef __MRC__
652 int result = creat (mac_pathname);
653 fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
654 return result;
655 #else /* not __MRC__ */
656 return creat (mac_pathname, mode);
657 #endif /* not __MRC__ */
662 #undef unlink
664 sys_unlink (const char *path)
666 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
667 int len;
668 char mac_pathname[MAXPATHLEN+1];
670 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
671 return -1;
673 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
674 if (len > -1)
675 fully_resolved_name[len] = '\0';
676 else
677 strcpy (fully_resolved_name, true_pathname);
679 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
680 return -1;
681 else
682 return unlink (mac_pathname);
686 #undef read
688 sys_read (int fildes, char *buf, int count)
690 if (fildes == 0) /* this should not be used for console input */
691 return -1;
692 else
693 #if __MSL__ >= 0x6000
694 return _read (fildes, buf, count);
695 #else
696 return read (fildes, buf, count);
697 #endif
701 #undef write
703 sys_write (int fildes, const char *buf, int count)
705 if (fildes == DEV_NULL_FD)
706 return count;
707 else
708 #if __MSL__ >= 0x6000
709 return _write (fildes, buf, count);
710 #else
711 return write (fildes, buf, count);
712 #endif
716 #undef rename
718 sys_rename (const char * old_name, const char * new_name)
720 char true_old_pathname[MAXPATHLEN+1], true_new_pathname[MAXPATHLEN+1];
721 char fully_resolved_old_name[MAXPATHLEN+1];
722 int len;
723 char mac_old_name[MAXPATHLEN+1], mac_new_name[MAXPATHLEN+1];
725 if (find_true_pathname (old_name, true_old_pathname, MAXPATHLEN+1) == -1)
726 return -1;
728 len = readlink (true_old_pathname, fully_resolved_old_name, MAXPATHLEN);
729 if (len > -1)
730 fully_resolved_old_name[len] = '\0';
731 else
732 strcpy (fully_resolved_old_name, true_old_pathname);
734 if (find_true_pathname (new_name, true_new_pathname, MAXPATHLEN+1) == -1)
735 return -1;
737 if (strcmp (fully_resolved_old_name, true_new_pathname) == 0)
738 return 0;
740 if (!posix_to_mac_pathname (fully_resolved_old_name,
741 mac_old_name,
742 MAXPATHLEN+1))
743 return -1;
745 if (!posix_to_mac_pathname(true_new_pathname, mac_new_name, MAXPATHLEN+1))
746 return -1;
748 /* If a file with new_name already exists, rename deletes the old
749 file in Unix. CW version fails in these situation. So we add a
750 call to unlink here. */
751 (void) unlink (mac_new_name);
753 return rename (mac_old_name, mac_new_name);
757 #undef fopen
758 extern FILE *fopen (const char *name, const char *mode);
759 FILE *
760 sys_fopen (const char *name, const char *mode)
762 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
763 int len;
764 char mac_pathname[MAXPATHLEN+1];
766 if (find_true_pathname (name, true_pathname, MAXPATHLEN+1) == -1)
767 return 0;
769 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
770 if (len > -1)
771 fully_resolved_name[len] = '\0';
772 else
773 strcpy (fully_resolved_name, true_pathname);
775 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
776 return 0;
777 else
779 #ifdef __MRC__
780 if (mode[0] == 'w' || mode[0] == 'a')
781 fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
782 #endif /* not __MRC__ */
783 return fopen (mac_pathname, mode);
788 #include <Events.h>
790 long target_ticks = 0;
792 #ifdef __MRC__
793 __sigfun alarm_signal_func = (__sigfun) 0;
794 #elif __MWERKS__
795 __signal_func_ptr alarm_signal_func = (__signal_func_ptr) 0;
796 #else /* not __MRC__ and not __MWERKS__ */
797 You lose!!!
798 #endif /* not __MRC__ and not __MWERKS__ */
801 /* These functions simulate SIG_ALRM. The stub for function signal
802 stores the signal handler function in alarm_signal_func if a
803 SIG_ALRM is encountered. check_alarm is called in XTread_socket,
804 which emacs calls periodically. A pending alarm is represented by
805 a non-zero target_ticks value. check_alarm calls the handler
806 function pointed to by alarm_signal_func if one has been set up and
807 an alarm is pending. */
809 void
810 check_alarm ()
812 if (target_ticks && TickCount () > target_ticks)
814 target_ticks = 0;
815 if (alarm_signal_func)
816 (*alarm_signal_func)(SIGALRM);
822 select (n, rfds, wfds, efds, timeout)
823 int n;
824 SELECT_TYPE *rfds;
825 SELECT_TYPE *wfds;
826 SELECT_TYPE *efds;
827 struct timeval *timeout;
829 #ifdef TARGET_API_MAC_CARBON
830 return 1;
831 #else /* not TARGET_API_MAC_CARBON */
832 EMACS_TIME end_time, now;
833 EventRecord e;
835 /* Can only handle wait for keyboard input. */
836 if (n > 1 || wfds || efds)
837 return -1;
839 EMACS_GET_TIME (end_time);
840 EMACS_ADD_TIME (end_time, end_time, *timeout);
844 /* Also return true if an event other than a keyDown has
845 occurred. This causes kbd_buffer_get_event in keyboard.c to
846 call read_avail_input which in turn calls XTread_socket to
847 poll for these events. Otherwise these never get processed
848 except but a very slow poll timer. */
849 if (FD_ISSET (0, rfds) && EventAvail (everyEvent, &e))
850 return 1;
852 /* Also check movement of the mouse. */
854 Point mouse_pos;
855 static Point old_mouse_pos = {-1, -1};
857 GetMouse (&mouse_pos);
858 if (!EqualPt (mouse_pos, old_mouse_pos))
860 old_mouse_pos = mouse_pos;
861 return 1;
865 WaitNextEvent (0, &e, 1UL, NULL); /* Accept no event; wait 1
866 tic. by T.I. */
868 EMACS_GET_TIME (now);
869 EMACS_SUB_TIME (now, end_time, now);
871 while (!EMACS_TIME_NEG_P (now));
873 return 0;
874 #endif /* not TARGET_API_MAC_CARBON */
878 /* Called in sys_select to wait for an alarm signal to arrive. */
881 pause ()
883 EventRecord e;
884 unsigned long tick;
886 if (!target_ticks) /* no alarm pending */
887 return -1;
889 if ((tick = TickCount ()) < target_ticks)
890 WaitNextEvent (0, &e, target_ticks - tick, NULL); /* Accept no event;
891 just wait. by T.I. */
893 target_ticks = 0;
894 if (alarm_signal_func)
895 (*alarm_signal_func)(SIGALRM);
897 return 0;
902 alarm (int seconds)
904 long remaining = target_ticks ? (TickCount () - target_ticks) / 60 : 0;
906 target_ticks = seconds ? TickCount () + 60 * seconds : 0;
908 return (remaining < 0) ? 0 : (unsigned int) remaining;
912 #undef signal
913 #ifdef __MRC__
914 extern __sigfun signal (int signal, __sigfun signal_func);
915 __sigfun
916 sys_signal (int signal_num, __sigfun signal_func)
917 #elif __MWERKS__
918 extern __signal_func_ptr signal (int signal, __signal_func_ptr signal_func);
919 __signal_func_ptr
920 sys_signal (int signal_num, __signal_func_ptr signal_func)
921 #else /* not __MRC__ and not __MWERKS__ */
922 You lose!!!
923 #endif /* not __MRC__ and not __MWERKS__ */
925 if (signal_num != SIGALRM)
926 return signal (signal_num, signal_func);
927 else
929 #ifdef __MRC__
930 __sigfun old_signal_func;
931 #elif __MWERKS__
932 __signal_func_ptr old_signal_func;
933 #else
934 You lose!!!
935 #endif
936 old_signal_func = alarm_signal_func;
937 alarm_signal_func = signal_func;
938 return old_signal_func;
943 /* gettimeofday should return the amount of time (in a timeval
944 structure) since midnight today. The toolbox function Microseconds
945 returns the number of microseconds (in a UnsignedWide value) since
946 the machine was booted. Also making this complicated is WideAdd,
947 WideSubtract, etc. take wide values. */
950 gettimeofday (tp)
951 struct timeval *tp;
953 static inited = 0;
954 static wide wall_clock_at_epoch, clicks_at_epoch;
955 UnsignedWide uw_microseconds;
956 wide w_microseconds;
957 time_t sys_time (time_t *);
959 /* If this function is called for the first time, record the number
960 of seconds since midnight and the number of microseconds since
961 boot at the time of this first call. */
962 if (!inited)
964 time_t systime;
965 inited = 1;
966 systime = sys_time (NULL);
967 /* Store microseconds since midnight in wall_clock_at_epoch. */
968 WideMultiply (systime, 1000000L, &wall_clock_at_epoch);
969 Microseconds (&uw_microseconds);
970 /* Store microseconds since boot in clicks_at_epoch. */
971 clicks_at_epoch.hi = uw_microseconds.hi;
972 clicks_at_epoch.lo = uw_microseconds.lo;
975 /* Get time since boot */
976 Microseconds (&uw_microseconds);
978 /* Convert to time since midnight*/
979 w_microseconds.hi = uw_microseconds.hi;
980 w_microseconds.lo = uw_microseconds.lo;
981 WideSubtract (&w_microseconds, &clicks_at_epoch);
982 WideAdd (&w_microseconds, &wall_clock_at_epoch);
983 tp->tv_sec = WideDivide (&w_microseconds, 1000000L, &tp->tv_usec);
985 return 0;
989 #ifdef __MRC__
990 unsigned int
991 sleep (unsigned int seconds)
993 unsigned long time_up;
994 EventRecord e;
996 time_up = TickCount () + seconds * 60;
997 while (TickCount () < time_up)
999 /* Accept no event; just wait. by T.I. */
1000 WaitNextEvent (0, &e, 30, NULL);
1003 return (0);
1005 #endif /* __MRC__ */
1008 /* The time functions adjust time values according to the difference
1009 between the Unix and CW epoches. */
1011 #undef gmtime
1012 extern struct tm *gmtime (const time_t *);
1013 struct tm *
1014 sys_gmtime (const time_t *timer)
1016 time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
1018 return gmtime (&unix_time);
1022 #undef localtime
1023 extern struct tm *localtime (const time_t *);
1024 struct tm *
1025 sys_localtime (const time_t *timer)
1027 #if __MSL__ >= 0x6000
1028 time_t unix_time = *timer;
1029 #else
1030 time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
1031 #endif
1033 return localtime (&unix_time);
1037 #undef ctime
1038 extern char *ctime (const time_t *);
1039 char *
1040 sys_ctime (const time_t *timer)
1042 #if __MSL__ >= 0x6000
1043 time_t unix_time = *timer;
1044 #else
1045 time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
1046 #endif
1048 return ctime (&unix_time);
1052 #undef time
1053 extern time_t time (time_t *);
1054 time_t
1055 sys_time (time_t *timer)
1057 #if __MSL__ >= 0x6000
1058 time_t mac_time = time (NULL);
1059 #else
1060 time_t mac_time = time (NULL) - CW_OR_MPW_UNIX_EPOCH_DIFF;
1061 #endif
1063 if (timer)
1064 *timer = mac_time;
1066 return mac_time;
1070 /* MPW strftime broken for "%p" format */
1071 #ifdef __MRC__
1072 #undef strftime
1073 #include <time.h>
1074 size_t
1075 sys_strftime (char * s, size_t maxsize, const char * format,
1076 const struct tm * timeptr)
1078 if (strcmp (format, "%p") == 0)
1080 if (maxsize < 3)
1081 return 0;
1082 if (timeptr->tm_hour < 12)
1084 strcpy (s, "AM");
1085 return 2;
1087 else
1089 strcpy (s, "PM");
1090 return 2;
1093 else
1094 return strftime (s, maxsize, format, timeptr);
1096 #endif /* __MRC__ */
1099 /* no subprocesses, empty wait */
1102 wait (int pid)
1104 return 0;
1108 void
1109 croak (char *badfunc)
1111 printf ("%s not yet implemented\r\n", badfunc);
1112 exit (1);
1116 char *
1117 index (const char * str, int chr)
1119 return strchr (str, chr);
1123 char *
1124 mktemp (char *template)
1126 int len, k;
1127 static seqnum = 0;
1129 len = strlen (template);
1130 k = len - 1;
1131 while (k >= 0 && template[k] == 'X')
1132 k--;
1134 k++; /* make k index of first 'X' */
1136 if (k < len)
1138 /* Zero filled, number of digits equal to the number of X's. */
1139 sprintf (&template[k], "%0*d", len-k, seqnum++);
1141 return template;
1143 else
1144 return 0;
1148 /* Emulate getpwuid, getpwnam and others. */
1150 #define PASSWD_FIELD_SIZE 256
1152 static char my_passwd_name[PASSWD_FIELD_SIZE];
1153 static char my_passwd_dir[MAXPATHLEN+1];
1155 static struct passwd my_passwd =
1157 my_passwd_name,
1158 my_passwd_dir,
1162 /* Initialized by main () in macterm.c to pathname of emacs directory. */
1164 char emacs_passwd_dir[MAXPATHLEN+1];
1166 char *
1167 getwd (char *);
1169 void
1170 init_emacs_passwd_dir ()
1172 int found = false;
1174 if (getwd (emacs_passwd_dir) && getwd (my_passwd_dir))
1176 /* Need pathname of first ancestor that begins with "emacs"
1177 since Mac emacs application is somewhere in the emacs-*
1178 tree. */
1179 int len = strlen (emacs_passwd_dir);
1180 int j = len - 1;
1181 /* j points to the "/" following the directory name being
1182 compared. */
1183 int i = j - 1;
1184 while (i >= 0 && !found)
1186 while (i >= 0 && emacs_passwd_dir[i] != '/')
1187 i--;
1188 if (emacs_passwd_dir[i] == '/' && i+5 < len)
1189 found = (strncmp (&(emacs_passwd_dir[i+1]), "emacs", 5) == 0);
1190 if (found)
1191 emacs_passwd_dir[j+1] = '\0';
1192 else
1194 j = i;
1195 i = j - 1;
1200 if (!found)
1202 /* Setting to "/" probably won't work but set it to something
1203 anyway. */
1204 strcpy (emacs_passwd_dir, "/");
1205 strcpy (my_passwd_dir, "/");
1210 static struct passwd emacs_passwd =
1212 "emacs",
1213 emacs_passwd_dir,
1216 static int my_passwd_inited = 0;
1219 static void
1220 init_my_passwd ()
1222 char **owner_name;
1224 /* Note: my_passwd_dir initialized in int_emacs_passwd_dir to
1225 directory where Emacs was started. */
1227 owner_name = (char **) GetResource ('STR ',-16096);
1228 if (owner_name)
1230 HLock (owner_name);
1231 BlockMove ((unsigned char *) *owner_name,
1232 (unsigned char *) my_passwd_name,
1233 *owner_name[0]+1);
1234 HUnlock (owner_name);
1235 p2cstr ((unsigned char *) my_passwd_name);
1237 else
1238 my_passwd_name[0] = 0;
1242 struct passwd *
1243 getpwuid (uid_t uid)
1245 if (!my_passwd_inited)
1247 init_my_passwd ();
1248 my_passwd_inited = 1;
1251 return &my_passwd;
1255 struct passwd *
1256 getpwnam (const char *name)
1258 if (strcmp (name, "emacs") == 0)
1259 return &emacs_passwd;
1261 if (!my_passwd_inited)
1263 init_my_passwd ();
1264 my_passwd_inited = 1;
1267 return &my_passwd;
1271 /* The functions fork, kill, sigsetmask, sigblock, request_sigio,
1272 setpgrp, setpriority, and unrequest_sigio are defined to be empty
1273 as in msdos.c. */
1277 fork ()
1279 return -1;
1284 kill (int x, int y)
1286 return -1;
1290 void
1291 sys_subshell ()
1293 error ("Can't spawn subshell");
1298 sigsetmask (int x)
1300 return 0;
1305 sigblock (int mask)
1307 return 0;
1311 void
1312 request_sigio (void)
1317 void
1318 unrequest_sigio (void)
1324 setpgrp ()
1326 return 0;
1330 /* No pipes yet. */
1333 pipe (int _fildes[2])
1335 errno = EACCES;
1336 return -1;
1340 /* Hard and symbolic links. */
1343 symlink (const char *name1, const char *name2)
1345 errno = ENOENT;
1346 return -1;
1351 link (const char *name1, const char *name2)
1353 errno = ENOENT;
1354 return -1;
1357 #endif /* ! MAC_OSX */
1359 /* Determine the path name of the file specified by VREFNUM, DIRID,
1360 and NAME and place that in the buffer PATH of length
1361 MAXPATHLEN. */
1363 path_from_vol_dir_name (char *path, int man_path_len, short vol_ref_num,
1364 long dir_id, ConstStr255Param name)
1366 Str255 dir_name;
1367 CInfoPBRec cipb;
1368 OSErr err;
1370 if (strlen (name) > man_path_len)
1371 return 0;
1373 memcpy (dir_name, name, name[0]+1);
1374 memcpy (path, name, name[0]+1);
1375 p2cstr (path);
1377 cipb.dirInfo.ioDrParID = dir_id;
1378 cipb.dirInfo.ioNamePtr = dir_name;
1382 cipb.dirInfo.ioVRefNum = vol_ref_num;
1383 cipb.dirInfo.ioFDirIndex = -1;
1384 cipb.dirInfo.ioDrDirID = cipb.dirInfo.ioDrParID;
1385 /* go up to parent each time */
1387 err = PBGetCatInfo (&cipb, false);
1388 if (err != noErr)
1389 return 0;
1391 p2cstr (dir_name);
1392 if (strlen (dir_name) + strlen (path) + 1 >= man_path_len)
1393 return 0;
1395 strcat (dir_name, ":");
1396 strcat (dir_name, path);
1397 /* attach to front since we're going up directory tree */
1398 strcpy (path, dir_name);
1400 while (cipb.dirInfo.ioDrDirID != fsRtDirID);
1401 /* stop when we see the volume's root directory */
1403 return 1; /* success */
1406 #ifndef MAC_OSX
1409 readlink (const char *path, char *buf, int bufsiz)
1411 char mac_sym_link_name[MAXPATHLEN+1];
1412 OSErr err;
1413 FSSpec fsspec;
1414 Boolean target_is_folder, was_aliased;
1415 Str255 directory_name, mac_pathname;
1416 CInfoPBRec cipb;
1418 if (posix_to_mac_pathname (path, mac_sym_link_name, MAXPATHLEN+1) == 0)
1419 return -1;
1421 c2pstr (mac_sym_link_name);
1422 err = FSMakeFSSpec (0, 0, mac_sym_link_name, &fsspec);
1423 if (err != noErr)
1425 errno = ENOENT;
1426 return -1;
1429 err = ResolveAliasFile (&fsspec, true, &target_is_folder, &was_aliased);
1430 if (err != noErr || !was_aliased)
1432 errno = ENOENT;
1433 return -1;
1436 if (path_from_vol_dir_name (mac_pathname, 255, fsspec.vRefNum, fsspec.parID,
1437 fsspec.name) == 0)
1439 errno = ENOENT;
1440 return -1;
1443 if (mac_to_posix_pathname (mac_pathname, buf, bufsiz) == 0)
1445 errno = ENOENT;
1446 return -1;
1449 return strlen (buf);
1453 /* Convert a path to one with aliases fully expanded. */
1455 static int
1456 find_true_pathname (const char *path, char *buf, int bufsiz)
1458 char *q, temp[MAXPATHLEN+1];
1459 const char *p;
1460 int len;
1462 if (bufsiz <= 0 || path == 0 || path[0] == '\0')
1463 return -1;
1465 buf[0] = '\0';
1467 p = path;
1468 if (*p == '/')
1469 q = strchr (p + 1, '/');
1470 else
1471 q = strchr (p, '/');
1472 len = 0; /* loop may not be entered, e.g., for "/" */
1474 while (q)
1476 strcpy (temp, buf);
1477 strncat (temp, p, q - p);
1478 len = readlink (temp, buf, bufsiz);
1479 if (len <= -1)
1481 if (strlen (temp) + 1 > bufsiz)
1482 return -1;
1483 strcpy (buf, temp);
1485 strcat (buf, "/");
1486 len++;
1487 p = q + 1;
1488 q = strchr(p, '/');
1491 if (len + strlen (p) + 1 >= bufsiz)
1492 return -1;
1494 strcat (buf, p);
1495 return len + strlen (p);
1499 mode_t
1500 umask (mode_t numask)
1502 static mode_t mask = 022;
1503 mode_t oldmask = mask;
1504 mask = numask;
1505 return oldmask;
1510 chmod (const char *path, mode_t mode)
1512 /* say it always succeed for now */
1513 return 0;
1518 dup (int oldd)
1520 #ifdef __MRC__
1521 return fcntl (oldd, F_DUPFD, 0);
1522 #elif __MWERKS__
1523 /* current implementation of fcntl in fcntl.mac.c simply returns old
1524 descriptor */
1525 return fcntl (oldd, F_DUPFD);
1526 #else
1527 You lose!!!
1528 #endif
1532 /* This is from the original sysdep.c. Emulate BSD dup2. First close
1533 newd if it already exists. Then, attempt to dup oldd. If not
1534 successful, call dup2 recursively until we are, then close the
1535 unsuccessful ones. */
1538 dup2 (int oldd, int newd)
1540 int fd, ret;
1542 close (newd);
1544 fd = dup (oldd);
1545 if (fd == -1)
1546 return -1;
1547 if (fd == newd)
1548 return newd;
1549 ret = dup2 (oldd, newd);
1550 close (fd);
1551 return ret;
1555 /* let it fail for now */
1557 char *
1558 sbrk (int incr)
1560 return (char *) -1;
1565 fsync (int fd)
1567 return 0;
1572 ioctl (int d, int request, void *argp)
1574 return -1;
1578 #ifdef __MRC__
1580 isatty (int fildes)
1582 if (fildes >=0 && fildes <= 2)
1583 return 1;
1584 else
1585 return 0;
1590 getgid ()
1592 return 100;
1597 getegid ()
1599 return 100;
1604 getuid ()
1606 return 200;
1611 geteuid ()
1613 return 200;
1615 #endif /* __MRC__ */
1618 #ifdef __MWERKS__
1619 #if __MSL__ < 0x6000
1620 #undef getpid
1622 getpid ()
1624 return 9999;
1626 #endif
1627 #endif /* __MWERKS__ */
1629 #endif /* ! MAC_OSX */
1632 /* Return the path to the directory in which Emacs can create
1633 temporary files. The MacOS "temporary items" directory cannot be
1634 used because it removes the file written by a process when it
1635 exits. In that sense it's more like "/dev/null" than "/tmp" (but
1636 again not exactly). And of course Emacs needs to read back the
1637 files written by its subprocesses. So here we write the files to a
1638 directory "Emacs" in the Preferences Folder. This directory is
1639 created if it does not exist. */
1641 char *
1642 get_temp_dir_name ()
1644 static char *temp_dir_name = NULL;
1645 short vol_ref_num;
1646 long dir_id;
1647 OSErr err;
1648 Str255 dir_name, full_path;
1649 CInfoPBRec cpb;
1650 char unix_dir_name[MAXPATHLEN+1];
1651 DIR *dir;
1653 /* Cache directory name with pointer temp_dir_name.
1654 Look for it only the first time. */
1655 if (!temp_dir_name)
1657 err = FindFolder (kOnSystemDisk, kPreferencesFolderType, kCreateFolder,
1658 &vol_ref_num, &dir_id);
1659 if (err != noErr)
1660 return NULL;
1662 if (!path_from_vol_dir_name (full_path, 255, vol_ref_num, dir_id, "\p"))
1663 return NULL;
1665 if (strlen (full_path) + 6 <= MAXPATHLEN)
1666 strcat (full_path, "Emacs:");
1667 else
1668 return NULL;
1670 if (!mac_to_posix_pathname (full_path, unix_dir_name, MAXPATHLEN+1))
1671 return NULL;
1673 dir = opendir (unix_dir_name); /* check whether temp directory exists */
1674 if (dir)
1675 closedir (dir);
1676 else if (mkdir (unix_dir_name, 0700) != 0) /* create it if not */
1677 return NULL;
1679 temp_dir_name = (char *) malloc (strlen (unix_dir_name) + 1);
1680 strcpy (temp_dir_name, unix_dir_name);
1683 return temp_dir_name;
1686 #ifndef MAC_OSX
1688 /* Allocate and construct an array of pointers to strings from a list
1689 of strings stored in a 'STR#' resource. The returned pointer array
1690 is stored in the style of argv and environ: if the 'STR#' resource
1691 contains numString strings, an pointer array with numString+1
1692 elements is returned in which the last entry contains a null
1693 pointer. The pointer to the pointer array is passed by pointer in
1694 parameter t. The resource ID of the 'STR#' resource is passed in
1695 parameter StringListID.
1698 void
1699 get_string_list (char ***t, short string_list_id)
1701 Handle h;
1702 Ptr p;
1703 int i, num_strings;
1705 h = GetResource ('STR#', string_list_id);
1706 if (h)
1708 HLock (h);
1709 p = *h;
1710 num_strings = * (short *) p;
1711 p += sizeof(short);
1712 *t = (char **) malloc (sizeof (char *) * (num_strings + 1));
1713 for (i = 0; i < num_strings; i++)
1715 short length = *p++;
1716 (*t)[i] = (char *) malloc (length + 1);
1717 strncpy ((*t)[i], p, length);
1718 (*t)[i][length] = '\0';
1719 p += length;
1721 (*t)[num_strings] = 0;
1722 HUnlock (h);
1724 else
1726 /* Return no string in case GetResource fails. Bug fixed by
1727 Ikegami Tsutomu. Caused MPW build to crash without sym -on
1728 option (no sym -on implies -opt local). */
1729 *t = (char **) malloc (sizeof (char *));
1730 (*t)[0] = 0;
1735 static char *
1736 get_path_to_system_folder ()
1738 short vol_ref_num;
1739 long dir_id;
1740 OSErr err;
1741 Str255 dir_name, full_path;
1742 CInfoPBRec cpb;
1743 static char system_folder_unix_name[MAXPATHLEN+1];
1744 DIR *dir;
1746 err = FindFolder (kOnSystemDisk, kSystemFolderType, kDontCreateFolder,
1747 &vol_ref_num, &dir_id);
1748 if (err != noErr)
1749 return NULL;
1751 if (!path_from_vol_dir_name (full_path, 255, vol_ref_num, dir_id, "\p"))
1752 return NULL;
1754 if (!mac_to_posix_pathname (full_path, system_folder_unix_name,
1755 MAXPATHLEN+1))
1756 return NULL;
1758 return system_folder_unix_name;
1762 char **environ;
1764 #define ENVIRON_STRING_LIST_ID 128
1766 /* Get environment variable definitions from STR# resource. */
1768 void
1769 init_environ ()
1771 int i;
1773 get_string_list (&environ, ENVIRON_STRING_LIST_ID);
1775 i = 0;
1776 while (environ[i])
1777 i++;
1779 /* Make HOME directory the one Emacs starts up in if not specified
1780 by resource. */
1781 if (getenv ("HOME") == NULL)
1783 environ = (char **) realloc (environ, sizeof (char *) * (i + 2));
1784 if (environ)
1786 environ[i] = (char *) malloc (strlen (my_passwd_dir) + 6);
1787 if (environ[i])
1789 strcpy (environ[i], "HOME=");
1790 strcat (environ[i], my_passwd_dir);
1792 environ[i+1] = 0;
1793 i++;
1797 /* Make HOME directory the one Emacs starts up in if not specified
1798 by resource. */
1799 if (getenv ("MAIL") == NULL)
1801 environ = (char **) realloc (environ, sizeof (char *) * (i + 2));
1802 if (environ)
1804 char * path_to_system_folder = get_path_to_system_folder ();
1805 environ[i] = (char *) malloc (strlen (path_to_system_folder) + 22);
1806 if (environ[i])
1808 strcpy (environ[i], "MAIL=");
1809 strcat (environ[i], path_to_system_folder);
1810 strcat (environ[i], "Eudora Folder/In");
1812 environ[i+1] = 0;
1818 /* Return the value of the environment variable NAME. */
1820 char *
1821 getenv (const char *name)
1823 int length = strlen(name);
1824 char **e;
1826 for (e = environ; *e != 0; e++)
1827 if (strncmp(*e, name, length) == 0 && (*e)[length] == '=')
1828 return &(*e)[length + 1];
1830 if (strcmp (name, "TMPDIR") == 0)
1831 return get_temp_dir_name ();
1833 return 0;
1837 #ifdef __MRC__
1838 /* see Interfaces&Libraries:Interfaces:CIncludes:signal.h */
1839 char *sys_siglist[] =
1841 "Zero is not a signal!!!",
1842 "Abort", /* 1 */
1843 "Interactive user interrupt", /* 2 */ "?",
1844 "Floating point exception", /* 4 */ "?", "?", "?",
1845 "Illegal instruction", /* 8 */ "?", "?", "?", "?", "?", "?", "?",
1846 "Segment violation", /* 16 */ "?", "?", "?", "?", "?", "?", "?",
1847 "?", "?", "?", "?", "?", "?", "?", "?",
1848 "Terminal" /* 32 */
1850 #elif __MWERKS__
1851 char *sys_siglist[] =
1853 "Zero is not a signal!!!",
1854 "Abort",
1855 "Floating point exception",
1856 "Illegal instruction",
1857 "Interactive user interrupt",
1858 "Segment violation",
1859 "Terminal"
1861 #else /* not __MRC__ and not __MWERKS__ */
1862 You lose!!!
1863 #endif /* not __MRC__ and not __MWERKS__ */
1866 #include <utsname.h>
1869 uname (struct utsname *name)
1871 char **system_name;
1872 system_name = GetString (-16413); /* IM - Resource Manager Reference */
1873 if (system_name)
1875 BlockMove (*system_name, name->nodename, (*system_name)[0]+1);
1876 p2cstr (name->nodename);
1877 return 0;
1879 else
1880 return -1;
1884 #include <Processes.h>
1885 #include <EPPC.h>
1887 /* Event class of HLE sent to subprocess. */
1888 const OSType kEmacsSubprocessSend = 'ESND';
1890 /* Event class of HLE sent back from subprocess. */
1891 const OSType kEmacsSubprocessReply = 'ERPY';
1894 char *
1895 mystrchr (char *s, char c)
1897 while (*s && *s != c)
1899 if (*s == '\\')
1900 s++;
1901 s++;
1904 if (*s)
1906 *s = '\0';
1907 return s;
1909 else
1910 return NULL;
1914 char *
1915 mystrtok (char *s)
1917 while (*s)
1918 s++;
1920 return s + 1;
1924 void
1925 mystrcpy (char *to, char *from)
1927 while (*from)
1929 if (*from == '\\')
1930 from++;
1931 *to++ = *from++;
1933 *to = '\0';
1937 /* Start a Mac subprocess. Arguments for it is passed in argv (null
1938 terminated). The process should run with the default directory
1939 "workdir", read input from "infn", and write output and error to
1940 "outfn" and "errfn", resp. The Process Manager call
1941 LaunchApplication is used to start the subprocess. We use high
1942 level events as the mechanism to pass arguments to the subprocess
1943 and to make Emacs wait for the subprocess to terminate and pass
1944 back a result code. The bulk of the code here packs the arguments
1945 into one message to be passed together with the high level event.
1946 Emacs also sometimes starts a subprocess using a shell to perform
1947 wildcard filename expansion. Since we don't really have a shell on
1948 the Mac, this case is detected and the starting of the shell is
1949 by-passed. We really need to add code here to do filename
1950 expansion to support such functionality. */
1953 run_mac_command (argv, workdir, infn, outfn, errfn)
1954 unsigned char **argv;
1955 const char *workdir;
1956 const char *infn, *outfn, *errfn;
1958 #ifdef TARGET_API_MAC_CARBON
1959 return -1;
1960 #else /* not TARGET_API_MAC_CARBON */
1961 char macappname[MAXPATHLEN+1], macworkdir[MAXPATHLEN+1];
1962 char macinfn[MAXPATHLEN+1], macoutfn[MAXPATHLEN+1], macerrfn[MAXPATHLEN+1];
1963 int paramlen, argc, newargc, j, retries;
1964 char **newargv, *param, *p;
1965 OSErr iErr;
1966 FSSpec spec;
1967 LaunchParamBlockRec lpbr;
1968 EventRecord send_event, reply_event;
1969 RgnHandle cursor_region_handle;
1970 TargetID targ;
1971 unsigned long ref_con, len;
1973 if (posix_to_mac_pathname (workdir, macworkdir, MAXPATHLEN+1) == 0)
1974 return -1;
1975 if (posix_to_mac_pathname (infn, macinfn, MAXPATHLEN+1) == 0)
1976 return -1;
1977 if (posix_to_mac_pathname (outfn, macoutfn, MAXPATHLEN+1) == 0)
1978 return -1;
1979 if (posix_to_mac_pathname (errfn, macerrfn, MAXPATHLEN+1) == 0)
1980 return -1;
1982 paramlen = strlen (macworkdir) + strlen (macinfn) + strlen (macoutfn)
1983 + strlen (macerrfn) + 4; /* count nulls at end of strings */
1985 argc = 0;
1986 while (argv[argc])
1987 argc++;
1989 if (argc == 0)
1990 return -1;
1992 /* If a subprocess is invoked with a shell, we receive 3 arguments
1993 of the form: "<path to emacs bins>/sh" "-c" "<path to emacs
1994 bins>/<command> <command args>" */
1995 j = strlen (argv[0]);
1996 if (j >= 3 && strcmp (argv[0]+j-3, "/sh") == 0
1997 && argc == 3 && strcmp (argv[1], "-c") == 0)
1999 char *command, *t, tempmacpathname[MAXPATHLEN+1];
2001 /* The arguments for the command in argv[2] are separated by
2002 spaces. Count them and put the count in newargc. */
2003 command = (char *) alloca (strlen (argv[2])+2);
2004 strcpy (command, argv[2]);
2005 if (command[strlen (command) - 1] != ' ')
2006 strcat (command, " ");
2008 t = command;
2009 newargc = 0;
2010 t = mystrchr (t, ' ');
2011 while (t)
2013 newargc++;
2014 t = mystrchr (t+1, ' ');
2017 newargv = (char **) alloca (sizeof (char *) * newargc);
2019 t = command;
2020 for (j = 0; j < newargc; j++)
2022 newargv[j] = (char *) alloca (strlen (t) + 1);
2023 mystrcpy (newargv[j], t);
2025 t = mystrtok (t);
2026 paramlen += strlen (newargv[j]) + 1;
2029 if (strncmp (newargv[0], "~emacs/", 7) == 0)
2031 if (posix_to_mac_pathname (newargv[0], tempmacpathname, MAXPATHLEN+1)
2032 == 0)
2033 return -1;
2035 else
2036 { /* sometimes Emacs call "sh" without a path for the command */
2037 #if 0
2038 char *t = (char *) alloca (strlen (newargv[0]) + 7 + 1);
2039 strcpy (t, "~emacs/");
2040 strcat (t, newargv[0]);
2041 #endif /* 0 */
2042 Lisp_Object path;
2043 openp (Vexec_path, build_string (newargv[0]), EXEC_SUFFIXES, &path,
2044 make_number (X_OK));
2046 if (NILP (path))
2047 return -1;
2048 if (posix_to_mac_pathname (XSTRING (path)->data, tempmacpathname,
2049 MAXPATHLEN+1) == 0)
2050 return -1;
2052 strcpy (macappname, tempmacpathname);
2054 else
2056 if (posix_to_mac_pathname (argv[0], macappname, MAXPATHLEN+1) == 0)
2057 return -1;
2059 newargv = (char **) alloca (sizeof (char *) * argc);
2060 newargc = argc;
2061 for (j = 1; j < argc; j++)
2063 if (strncmp (argv[j], "~emacs/", 7) == 0)
2065 char *t = strchr (argv[j], ' ');
2066 if (t)
2068 char tempcmdname[MAXPATHLEN+1], tempmaccmdname[MAXPATHLEN+1];
2069 strncpy (tempcmdname, argv[j], t-argv[j]);
2070 tempcmdname[t-argv[j]] = '\0';
2071 if (posix_to_mac_pathname (tempcmdname, tempmaccmdname,
2072 MAXPATHLEN+1) == 0)
2073 return -1;
2074 newargv[j] = (char *) alloca (strlen (tempmaccmdname)
2075 + strlen (t) + 1);
2076 strcpy (newargv[j], tempmaccmdname);
2077 strcat (newargv[j], t);
2079 else
2081 char tempmaccmdname[MAXPATHLEN+1];
2082 if (posix_to_mac_pathname (argv[j], tempmaccmdname,
2083 MAXPATHLEN+1) == 0)
2084 return -1;
2085 newargv[j] = (char *) alloca (strlen (tempmaccmdname)+1);
2086 strcpy (newargv[j], tempmaccmdname);
2089 else
2090 newargv[j] = argv[j];
2091 paramlen += strlen (newargv[j]) + 1;
2095 /* After expanding all the arguments, we now know the length of the
2096 parameter block to be sent to the subprocess as a message
2097 attached to the HLE. */
2098 param = (char *) malloc (paramlen + 1);
2099 if (!param)
2100 return -1;
2102 p = param;
2103 *p++ = newargc;
2104 /* first byte of message contains number of arguments for command */
2105 strcpy (p, macworkdir);
2106 p += strlen (macworkdir);
2107 *p++ = '\0';
2108 /* null terminate strings sent so it's possible to use strcpy over there */
2109 strcpy (p, macinfn);
2110 p += strlen (macinfn);
2111 *p++ = '\0';
2112 strcpy (p, macoutfn);
2113 p += strlen (macoutfn);
2114 *p++ = '\0';
2115 strcpy (p, macerrfn);
2116 p += strlen (macerrfn);
2117 *p++ = '\0';
2118 for (j = 1; j < newargc; j++)
2120 strcpy (p, newargv[j]);
2121 p += strlen (newargv[j]);
2122 *p++ = '\0';
2125 c2pstr (macappname);
2127 iErr = FSMakeFSSpec (0, 0, macappname, &spec);
2129 if (iErr != noErr)
2131 free (param);
2132 return -1;
2135 lpbr.launchBlockID = extendedBlock;
2136 lpbr.launchEPBLength = extendedBlockLen;
2137 lpbr.launchControlFlags = launchContinue + launchNoFileFlags;
2138 lpbr.launchAppSpec = &spec;
2139 lpbr.launchAppParameters = NULL;
2141 iErr = LaunchApplication (&lpbr); /* call the subprocess */
2142 if (iErr != noErr)
2144 free (param);
2145 return -1;
2148 send_event.what = kHighLevelEvent;
2149 send_event.message = kEmacsSubprocessSend;
2150 /* Event ID stored in "where" unused */
2152 retries = 3;
2153 /* OS may think current subprocess has terminated if previous one
2154 terminated recently. */
2157 iErr = PostHighLevelEvent (&send_event, &lpbr.launchProcessSN, 0, param,
2158 paramlen + 1, receiverIDisPSN);
2160 while (iErr == sessClosedErr && retries-- > 0);
2162 if (iErr != noErr)
2164 free (param);
2165 return -1;
2168 cursor_region_handle = NewRgn ();
2170 /* Wait for the subprocess to finish, when it will send us a ERPY
2171 high level event. */
2172 while (1)
2173 if (WaitNextEvent (highLevelEventMask, &reply_event, 180,
2174 cursor_region_handle)
2175 && reply_event.message == kEmacsSubprocessReply)
2176 break;
2178 /* The return code is sent through the refCon */
2179 iErr = AcceptHighLevelEvent (&targ, &ref_con, NULL, &len);
2180 if (iErr != noErr)
2182 DisposeHandle ((Handle) cursor_region_handle);
2183 free (param);
2184 return -1;
2187 DisposeHandle ((Handle) cursor_region_handle);
2188 free (param);
2190 return ref_con;
2191 #endif /* not TARGET_API_MAC_CARBON */
2195 DIR *
2196 opendir (const char *dirname)
2198 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
2199 char mac_pathname[MAXPATHLEN+1], vol_name[MAXPATHLEN+1];
2200 DIR *dirp;
2201 CInfoPBRec cipb;
2202 HVolumeParam vpb;
2203 int len, vol_name_len;
2205 if (find_true_pathname (dirname, true_pathname, MAXPATHLEN+1) == -1)
2206 return 0;
2208 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
2209 if (len > -1)
2210 fully_resolved_name[len] = '\0';
2211 else
2212 strcpy (fully_resolved_name, true_pathname);
2214 dirp = (DIR *) malloc (sizeof(DIR));
2215 if (!dirp)
2216 return 0;
2218 /* Handle special case when dirname is "/": sets up for readir to
2219 get all mount volumes. */
2220 if (strcmp (fully_resolved_name, "/") == 0)
2222 dirp->getting_volumes = 1; /* special all mounted volumes DIR struct */
2223 dirp->current_index = 1; /* index for first volume */
2224 return dirp;
2227 /* Handle typical cases: not accessing all mounted volumes. */
2228 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
2229 return 0;
2231 /* Emacs calls opendir without the trailing '/', Mac needs trailing ':' */
2232 len = strlen (mac_pathname);
2233 if (mac_pathname[len - 1] != ':' && len < MAXPATHLEN)
2234 strcat (mac_pathname, ":");
2236 /* Extract volume name */
2237 vol_name_len = strchr (mac_pathname, ':') - mac_pathname;
2238 strncpy (vol_name, mac_pathname, vol_name_len);
2239 vol_name[vol_name_len] = '\0';
2240 strcat (vol_name, ":");
2242 c2pstr (mac_pathname);
2243 cipb.hFileInfo.ioNamePtr = mac_pathname;
2244 /* using full pathname so vRefNum and DirID ignored */
2245 cipb.hFileInfo.ioVRefNum = 0;
2246 cipb.hFileInfo.ioDirID = 0;
2247 cipb.hFileInfo.ioFDirIndex = 0;
2248 /* set to 0 to get information about specific dir or file */
2250 errno = PBGetCatInfo (&cipb, false);
2251 if (errno != noErr)
2253 errno = ENOENT;
2254 return 0;
2257 if (!(cipb.hFileInfo.ioFlAttrib & 0x10)) /* bit 4 = 1 for directories */
2258 return 0; /* not a directory */
2260 dirp->dir_id = cipb.dirInfo.ioDrDirID; /* used later in readdir */
2261 dirp->getting_volumes = 0;
2262 dirp->current_index = 1; /* index for first file/directory */
2264 c2pstr (vol_name);
2265 vpb.ioNamePtr = vol_name;
2266 /* using full pathname so vRefNum and DirID ignored */
2267 vpb.ioVRefNum = 0;
2268 vpb.ioVolIndex = -1;
2269 errno = PBHGetVInfo ((union HParamBlockRec *) &vpb, false);
2270 if (errno != noErr)
2272 errno = ENOENT;
2273 return 0;
2276 dirp->vol_ref_num = vpb.ioVRefNum;
2278 return dirp;
2282 closedir (DIR *dp)
2284 free (dp);
2286 return 0;
2290 struct dirent *
2291 readdir (DIR *dp)
2293 HParamBlockRec hpblock;
2294 CInfoPBRec cipb;
2295 static struct dirent s_dirent;
2296 static Str255 s_name;
2297 int done;
2298 char *p;
2300 /* Handle the root directory containing the mounted volumes. Call
2301 PBHGetVInfo specifying an index to obtain the info for a volume.
2302 PBHGetVInfo returns an error when it receives an index beyond the
2303 last volume, at which time we should return a nil dirent struct
2304 pointer. */
2305 if (dp->getting_volumes)
2307 hpblock.volumeParam.ioNamePtr = s_name;
2308 hpblock.volumeParam.ioVRefNum = 0;
2309 hpblock.volumeParam.ioVolIndex = dp->current_index;
2311 errno = PBHGetVInfo (&hpblock, false);
2312 if (errno != noErr)
2314 errno = ENOENT;
2315 return 0;
2318 p2cstr (s_name);
2319 strcat (s_name, "/"); /* need "/" for stat to work correctly */
2321 dp->current_index++;
2323 s_dirent.d_ino = hpblock.volumeParam.ioVRefNum;
2324 s_dirent.d_name = s_name;
2326 return &s_dirent;
2328 else
2330 cipb.hFileInfo.ioVRefNum = dp->vol_ref_num;
2331 cipb.hFileInfo.ioNamePtr = s_name;
2332 /* location to receive filename returned */
2334 /* return only visible files */
2335 done = false;
2336 while (!done)
2338 cipb.hFileInfo.ioDirID = dp->dir_id;
2339 /* directory ID found by opendir */
2340 cipb.hFileInfo.ioFDirIndex = dp->current_index;
2342 errno = PBGetCatInfo (&cipb, false);
2343 if (errno != noErr)
2345 errno = ENOENT;
2346 return 0;
2349 /* insist on an visibile entry */
2350 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* directory? */
2351 done = !(cipb.dirInfo.ioDrUsrWds.frFlags & fInvisible);
2352 else
2353 done = !(cipb.hFileInfo.ioFlFndrInfo.fdFlags & fInvisible);
2355 dp->current_index++;
2358 p2cstr (s_name);
2360 p = s_name;
2361 while (*p)
2363 if (*p == '/')
2364 *p = ':';
2365 p++;
2368 s_dirent.d_ino = cipb.dirInfo.ioDrDirID;
2369 /* value unimportant: non-zero for valid file */
2370 s_dirent.d_name = s_name;
2372 return &s_dirent;
2377 char *
2378 getwd (char *path)
2380 char mac_pathname[MAXPATHLEN+1];
2381 Str255 directory_name;
2382 OSErr errno;
2383 CInfoPBRec cipb;
2385 if (path_from_vol_dir_name (mac_pathname, 255, 0, 0, "\p") == 0)
2386 return NULL;
2388 if (mac_to_posix_pathname (mac_pathname, path, MAXPATHLEN+1) == 0)
2389 return 0;
2390 else
2391 return path;
2394 #endif /* ! MAC_OSX */
2397 void
2398 initialize_applescript ()
2400 AEDesc null_desc;
2401 OSAError osaerror;
2403 /* if open fails, as_scripting_component is set to NULL. Its
2404 subsequent use in OSA calls will fail with badComponentInstance
2405 error. */
2406 as_scripting_component = OpenDefaultComponent (kOSAComponentType,
2407 kAppleScriptSubtype);
2409 null_desc.descriptorType = typeNull;
2410 null_desc.dataHandle = 0;
2411 osaerror = OSAMakeContext (as_scripting_component, &null_desc,
2412 kOSANullScript, &as_script_context);
2413 if (osaerror)
2414 as_script_context = kOSANullScript;
2415 /* use default context if create fails */
2419 void terminate_applescript()
2421 OSADispose (as_scripting_component, as_script_context);
2422 CloseComponent (as_scripting_component);
2426 /* Compile and execute the AppleScript SCRIPT and return the error
2427 status as function value. A zero is returned if compilation and
2428 execution is successful, in which case RESULT returns a pointer to
2429 a string containing the resulting script value. Otherwise, the Mac
2430 error code is returned and RESULT returns a pointer to an error
2431 string. In both cases the caller should deallocate the storage
2432 used by the string pointed to by RESULT if it is non-NULL. For
2433 documentation on the MacOS scripting architecture, see Inside
2434 Macintosh - Interapplication Communications: Scripting Components. */
2436 static long
2437 do_applescript (char *script, char **result)
2439 AEDesc script_desc, result_desc, error_desc;
2440 OSErr error;
2441 OSAError osaerror;
2442 long length;
2444 *result = 0;
2446 error = AECreateDesc (typeChar, script, strlen(script), &script_desc);
2447 if (error)
2448 return error;
2450 osaerror = OSADoScript (as_scripting_component, &script_desc, kOSANullScript,
2451 typeChar, kOSAModeNull, &result_desc);
2453 if (osaerror == errOSAScriptError)
2455 /* error executing AppleScript: retrieve error message */
2456 if (!OSAScriptError (as_scripting_component, kOSAErrorMessage, typeChar,
2457 &error_desc))
2459 #if TARGET_API_MAC_CARBON
2460 length = AEGetDescDataSize (&error_desc);
2461 *result = (char *) xmalloc (length + 1);
2462 if (*result)
2464 AEGetDescData (&error_desc, *result, length);
2465 *(*result + length) = '\0';
2467 #else /* not TARGET_API_MAC_CARBON */
2468 HLock (error_desc.dataHandle);
2469 length = GetHandleSize(error_desc.dataHandle);
2470 *result = (char *) xmalloc (length + 1);
2471 if (*result)
2473 memcpy (*result, *(error_desc.dataHandle), length);
2474 *(*result + length) = '\0';
2476 HUnlock (error_desc.dataHandle);
2477 #endif /* not TARGET_API_MAC_CARBON */
2478 AEDisposeDesc (&error_desc);
2481 else if (osaerror == noErr) /* success: retrieve resulting script value */
2483 #if TARGET_API_MAC_CARBON
2484 length = AEGetDescDataSize (&result_desc);
2485 *result = (char *) xmalloc (length + 1);
2486 if (*result)
2488 AEGetDescData (&result_desc, *result, length);
2489 *(*result + length) = '\0';
2491 #else /* not TARGET_API_MAC_CARBON */
2492 HLock (result_desc.dataHandle);
2493 length = GetHandleSize(result_desc.dataHandle);
2494 *result = (char *) xmalloc (length + 1);
2495 if (*result)
2497 memcpy (*result, *(result_desc.dataHandle), length);
2498 *(*result + length) = '\0';
2500 HUnlock (result_desc.dataHandle);
2501 #endif /* not TARGET_API_MAC_CARBON */
2504 AEDisposeDesc (&script_desc);
2505 AEDisposeDesc (&result_desc);
2507 return osaerror;
2511 DEFUN ("do-applescript", Fdo_applescript, Sdo_applescript, 1, 1, 0,
2512 doc: /* Compile and execute AppleScript SCRIPT and retrieve and return the result.
2513 If compilation and execution are successful, the resulting script
2514 value is returned as a string. Otherwise the function aborts and
2515 displays the error message returned by the AppleScript scripting
2516 component. */)
2517 (script)
2518 Lisp_Object script;
2520 char *result, *temp;
2521 Lisp_Object lisp_result;
2522 long status;
2524 CHECK_STRING (script);
2526 status = do_applescript (XSTRING (script)->data, &result);
2527 if (status)
2529 if (!result)
2530 error ("AppleScript error %ld", status);
2531 else
2533 /* Unfortunately only OSADoScript in do_applescript knows how
2534 how large the resulting script value or error message is
2535 going to be and therefore as caller memory must be
2536 deallocated here. It is necessary to free the error
2537 message before calling error to avoid a memory leak. */
2538 temp = (char *) alloca (strlen (result) + 1);
2539 strcpy (temp, result);
2540 xfree (result);
2541 error (temp);
2544 else
2546 lisp_result = build_string (result);
2547 xfree (result);
2548 return lisp_result;
2553 DEFUN ("mac-file-name-to-posix", Fmac_file_name_to_posix,
2554 Smac_file_name_to_posix, 1, 1, 0,
2555 doc: /* Convert Macintosh filename to Posix form. */)
2556 (mac_filename)
2557 Lisp_Object mac_filename;
2559 char posix_filename[MAXPATHLEN+1];
2561 CHECK_STRING (mac_filename);
2563 if (mac_to_posix_pathname (XSTRING (mac_filename)->data, posix_filename,
2564 MAXPATHLEN))
2565 return build_string (posix_filename);
2566 else
2567 return Qnil;
2571 DEFUN ("posix-file-name-to-mac", Fposix_file_name_to_mac,
2572 Sposix_file_name_to_mac, 1, 1, 0,
2573 doc: /* Convert Posix filename to Mac form. */)
2574 (posix_filename)
2575 Lisp_Object posix_filename;
2577 char mac_filename[MAXPATHLEN+1];
2579 CHECK_STRING (posix_filename);
2581 if (posix_to_mac_pathname (XSTRING (posix_filename)->data, mac_filename,
2582 MAXPATHLEN))
2583 return build_string (mac_filename);
2584 else
2585 return Qnil;
2589 /* set interprogram-paste-function to mac-paste-function in mac-win.el
2590 to enable Emacs to obtain the contents of the Mac clipboard. */
2591 DEFUN ("mac-paste-function", Fmac_paste_function, Smac_paste_function, 0, 0, 0,
2592 doc: /* Return the contents of the Mac clipboard as a string. */)
2595 #if TARGET_API_MAC_CARBON
2596 ScrapRef scrap;
2597 ScrapFlavorFlags sff;
2598 Size s;
2599 int i;
2600 char *data;
2602 if (GetCurrentScrap (&scrap) != noErr)
2603 return Qnil;
2605 if (GetScrapFlavorFlags (scrap, kScrapFlavorTypeText, &sff) != noErr)
2606 return Qnil;
2608 if (GetScrapFlavorSize (scrap, kScrapFlavorTypeText, &s) != noErr)
2609 return Qnil;
2611 if ((data = (char*) alloca (s)) == NULL)
2612 return Qnil;
2614 if (GetScrapFlavorData (scrap, kScrapFlavorTypeText, &s, data) != noErr
2615 || s == 0)
2616 return Qnil;
2618 /* Emacs expects clipboard contents have Unix-style eol's */
2619 for (i = 0; i < s; i++)
2620 if (data[i] == '\r')
2621 data[i] = '\n';
2623 return make_string (data, s);
2624 #else /* not TARGET_API_MAC_CARBON */
2625 Lisp_Object value;
2626 Handle my_handle;
2627 long scrap_offset, rc, i;
2629 my_handle = NewHandle (0); /* allocate 0-length data area */
2631 rc = GetScrap (my_handle, 'TEXT', &scrap_offset);
2632 if (rc < 0)
2633 return Qnil;
2635 HLock (my_handle);
2637 /* Emacs expects clipboard contents have Unix-style eol's */
2638 for (i = 0; i < rc; i++)
2639 if ((*my_handle)[i] == '\r')
2640 (*my_handle)[i] = '\n';
2642 value = make_string (*my_handle, rc);
2644 HUnlock (my_handle);
2646 DisposeHandle (my_handle);
2648 return value;
2649 #endif /* not TARGET_API_MAC_CARBON */
2653 /* set interprogram-cut-function to mac-cut-function in mac-win.el
2654 to enable Emacs to write the top of the kill-ring to the Mac clipboard. */
2655 DEFUN ("mac-cut-function", Fmac_cut_function, Smac_cut_function, 1, 2, 0,
2656 doc: /* Put the value of the string parameter to the Mac clipboard. */)
2657 (value, push)
2658 Lisp_Object value, push;
2660 char *buf;
2661 int len, i;
2663 /* fixme: ignore the push flag for now */
2665 CHECK_STRING (value);
2667 len = XSTRING (value)->size;
2668 buf = (char *) alloca (len+1);
2669 bcopy (XSTRING (value)->data, buf, len);
2670 buf[len] = '\0';
2672 /* convert to Mac-style eol's before sending to clipboard */
2673 for (i = 0; i < len; i++)
2674 if (buf[i] == '\n')
2675 buf[i] = '\r';
2677 #if TARGET_API_MAC_CARBON
2679 ScrapRef scrap;
2680 ClearCurrentScrap ();
2681 if (GetCurrentScrap (&scrap) != noErr)
2682 error ("cannot get current scrap");
2684 if (PutScrapFlavor (scrap, kScrapFlavorTypeText, kScrapFlavorMaskNone, len,
2685 buf) != noErr)
2686 error ("cannot put to scrap");
2688 #else /* not TARGET_API_MAC_CARBON */
2689 ZeroScrap ();
2690 PutScrap (len, 'TEXT', buf);
2691 #endif /* not TARGET_API_MAC_CARBON */
2693 return Qnil;
2697 DEFUN ("x-selection-exists-p", Fx_selection_exists_p, Sx_selection_exists_p,
2698 0, 1, 0,
2699 doc: /* Whether there is an owner for the given X Selection.
2700 The arg should be the name of the selection in question, typically one of
2701 the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.
2702 \(Those are literal upper-case symbol names, since that's what X expects.)
2703 For convenience, the symbol nil is the same as `PRIMARY',
2704 and t is the same as `SECONDARY'. */)
2705 (selection)
2706 Lisp_Object selection;
2708 CHECK_SYMBOL (selection);
2710 /* Return nil for PRIMARY and SECONDARY selections; for CLIPBOARD, check
2711 if the clipboard currently has valid text format contents. */
2713 if (EQ (selection, QCLIPBOARD))
2715 Lisp_Object val = Qnil;
2717 #if TARGET_API_MAC_CARBON
2718 ScrapRef scrap;
2719 ScrapFlavorFlags sff;
2721 if (GetCurrentScrap (&scrap) == noErr)
2722 if (GetScrapFlavorFlags (scrap, kScrapFlavorTypeText, &sff) == noErr)
2723 val = Qt;
2724 #else /* not TARGET_API_MAC_CARBON */
2725 Handle my_handle;
2726 long rc, scrap_offset;
2728 my_handle = NewHandle (0);
2730 rc = GetScrap (my_handle, 'TEXT', &scrap_offset);
2731 if (rc >= 0)
2732 val = Qt;
2734 DisposeHandle (my_handle);
2735 #endif /* not TARGET_API_MAC_CARBON */
2737 return val;
2739 return Qnil;
2743 void
2744 syms_of_mac ()
2746 QCLIPBOARD = intern ("CLIPBOARD");
2747 staticpro (&QCLIPBOARD);
2749 defsubr (&Smac_paste_function);
2750 defsubr (&Smac_cut_function);
2751 #if 0
2752 defsubr (&Sx_selection_exists_p);
2753 #endif /* 0 */
2755 defsubr (&Sdo_applescript);
2756 defsubr (&Smac_file_name_to_posix);
2757 defsubr (&Sposix_file_name_to_mac);