(sentence-end-double-space, sentence-end-without-period): Move to paragraphs.
[emacs.git] / mac / src / mac.c
blob473273f13b7d3f1f0e39a9433ed08f19a2f885da
1 /* Unix emulation routines for GNU Emacs on the Mac OS.
2 Copyright (C) 2000 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
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@users.sourceforge.net). */
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 #include <Files.h>
38 #include <MacTypes.h>
39 #include <TextUtils.h>
40 #include <Folders.h>
41 #include <Resources.h>
42 #include <Aliases.h>
43 #include <FixMath.h>
44 #include <Timer.h>
45 #include <OSA.h>
46 #include <AppleScript.h>
48 #include "lisp.h"
49 #include "process.h"
50 #include "sysselect.h"
51 #include "systime.h"
53 Lisp_Object QCLIPBOARD;
55 /* An instance of the AppleScript component. */
56 static ComponentInstance as_scripting_component;
57 /* The single script context used for all script executions. */
58 static OSAID as_script_context;
61 /* When converting from Mac to Unix pathnames, /'s in folder names are
62 converted to :'s. This function, used in copying folder names,
63 performs a strncat and converts all character a to b in the copy of
64 the string s2 appended to the end of s1. */
66 void
67 string_cat_and_replace (char *s1, const char *s2, int n, char a, char b)
69 int l1 = strlen (s1);
70 int l2 = strlen (s2);
71 char *p = s1 + l1;
72 int i;
74 strncat (s1, s2, n);
75 for (i = 0; i < l2; i++)
77 if (*p == a)
78 *p = b;
79 p++;
84 /* Convert a Mac pathname to Unix form. A Mac full pathname is one
85 that does not begin with a ':' and contains at least one ':'. A Mac
86 full pathname causes an '/' to be prepended to the Unix pathname.
87 The algorithm for the rest of the pathname is as follows:
88 For each segment between two ':',
89 if it is non-null, copy as is and then add a '/' at the end,
90 otherwise, insert a "../" into the Unix pathname.
91 Returns 1 if successful; 0 if fails. */
93 int
94 mac_to_posix_pathname (const char *mfn, char *ufn, int ufnbuflen)
96 const char *p, *q, *pe;
98 strcpy (ufn, "");
100 if (*mfn == '\0')
101 return 1;
103 p = strchr (mfn, ':');
104 if (p != 0 && p != mfn) /* full pathname */
105 strcat (ufn, "/");
107 p = mfn;
108 if (*p == ':')
109 p++;
111 pe = mfn + strlen (mfn);
112 while (p < pe)
114 q = strchr (p, ':');
115 if (q)
117 if (q == p)
118 { /* two consecutive ':' */
119 if (strlen (ufn) + 3 >= ufnbuflen)
120 return 0;
121 strcat (ufn, "../");
123 else
125 if (strlen (ufn) + (q - p) + 1 >= ufnbuflen)
126 return 0;
127 string_cat_and_replace (ufn, p, q - p, '/', ':');
128 strcat (ufn, "/");
130 p = q + 1;
132 else
134 if (strlen (ufn) + (pe - p) >= ufnbuflen)
135 return 0;
136 string_cat_and_replace (ufn, p, pe - p, '/', ':');
137 /* no separator for last one */
138 p = pe;
142 return 1;
146 extern char *get_temp_dir_name ();
149 /* Convert a Unix pathname to Mac form. Approximately reverse of the
150 above in algorithm. */
153 posix_to_mac_pathname (const char *ufn, char *mfn, int mfnbuflen)
155 const char *p, *q, *pe;
156 char expanded_pathname[MAXPATHLEN+1];
158 strcpy (mfn, "");
160 if (*ufn == '\0')
161 return 1;
163 p = ufn;
165 /* Check for and handle volume names. Last comparison: strangely
166 somewhere "/.emacs" is passed. A temporary fix for now. */
167 if (*p == '/' && strchr (p+1, '/') == NULL && strcmp (p, "/.emacs") != 0)
169 if (strlen (p) + 1 > mfnbuflen)
170 return 0;
171 strcpy (mfn, p+1);
172 strcat (mfn, ":");
173 return 1;
176 /* expand to emacs dir found by init_emacs_passwd_dir */
177 if (strncmp (p, "~emacs/", 7) == 0)
179 struct passwd *pw = getpwnam ("emacs");
180 p += 7;
181 if (strlen (pw->pw_dir) + strlen (p) > MAXPATHLEN)
182 return 0;
183 strcpy (expanded_pathname, pw->pw_dir);
184 strcat (expanded_pathname, p);
185 p = expanded_pathname;
186 /* now p points to the pathname with emacs dir prefix */
188 else if (strncmp (p, "/tmp/", 5) == 0)
190 char *t = get_temp_dir_name ();
191 p += 5;
192 if (strlen (t) + strlen (p) > MAXPATHLEN)
193 return 0;
194 strcpy (expanded_pathname, t);
195 strcat (expanded_pathname, p);
196 p = expanded_pathname;
197 /* now p points to the pathname with emacs dir prefix */
199 else if (*p != '/') /* relative pathname */
200 strcat (mfn, ":");
202 if (*p == '/')
203 p++;
205 pe = p + strlen (p);
206 while (p < pe)
208 q = strchr (p, '/');
209 if (q)
211 if (q - p == 2 && *p == '.' && *(p+1) == '.')
213 if (strlen (mfn) + 1 >= mfnbuflen)
214 return 0;
215 strcat (mfn, ":");
217 else
219 if (strlen (mfn) + (q - p) + 1 >= mfnbuflen)
220 return 0;
221 string_cat_and_replace (mfn, p, q - p, ':', '/');
222 strcat (mfn, ":");
224 p = q + 1;
226 else
228 if (strlen (mfn) + (pe - p) >= mfnbuflen)
229 return 0;
230 string_cat_and_replace (mfn, p, pe - p, ':', '/');
231 p = pe;
235 return 1;
239 /* The following functions with "sys_" prefix are stubs to Unix
240 functions that have already been implemented by CW or MPW. The
241 calls to them in Emacs source course are #define'd to call the sys_
242 versions by the header files s-mac.h. In these stubs pathnames are
243 converted between their Unix and Mac forms. */
246 /* Unix epoch is Jan 1, 1970 while Mac epoch is Jan 1, 1904: 66 years
247 + 17 leap days. These are for adjusting time values returned by
248 MacOS Toolbox functions. */
250 #define MAC_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
252 #ifdef __MWERKS__
253 #ifndef CODEWARRIOR_VERSION_6
254 /* CW Pro 5 epoch is Jan 1, 1900 (aaarghhhhh!); remember, 1900 is not
255 a leap year! This is for adjusting time_t values returned by MSL
256 functions. */
257 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 70 + 17) * 24 * 60 * 60)
258 #else
259 /* CW changes Pro 6 to following Unix! */
260 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
261 #endif
262 #elif __MRC__
263 /* MPW library functions follow Unix (confused?). */
264 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
265 #else
266 You lose!!!
267 #endif
270 /* Define our own stat function for both MrC and CW. The reason for
271 doing this: "stat" is both the name of a struct and function name:
272 can't use the same trick like that for sys_open, sys_close, etc. to
273 redirect Emacs's calls to our own version that converts Unix style
274 filenames to Mac style filename because all sorts of compilation
275 errors will be generated if stat is #define'd to be sys_stat. */
278 stat_noalias (const char *path, struct stat *buf)
280 char mac_pathname[MAXPATHLEN+1];
281 CInfoPBRec cipb;
283 if (posix_to_mac_pathname (path, mac_pathname, MAXPATHLEN+1) == 0)
284 return -1;
286 c2pstr (mac_pathname);
287 cipb.hFileInfo.ioNamePtr = mac_pathname;
288 cipb.hFileInfo.ioVRefNum = 0;
289 cipb.hFileInfo.ioDirID = 0;
290 cipb.hFileInfo.ioFDirIndex = 0;
291 /* set to 0 to get information about specific dir or file */
293 errno = PBGetCatInfo (&cipb, false);
294 if (errno == -43) /* -43: fnfErr defined in Errors.h */
295 errno = ENOENT;
296 if (errno != noErr)
297 return -1;
299 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* bit 4 = 1 for directories */
301 buf->st_mode = S_IFDIR | S_IREAD | S_IEXEC;
303 if (!(cipb.hFileInfo.ioFlAttrib & 0x1))
304 buf->st_mode |= S_IWRITE; /* bit 1 = 1 for locked files/directories */
305 buf->st_ino = cipb.dirInfo.ioDrDirID;
306 buf->st_dev = cipb.dirInfo.ioVRefNum;
307 buf->st_size = cipb.dirInfo.ioDrNmFls;
308 /* size of dir = number of files and dirs */
309 buf->st_atime
310 = buf->st_mtime
311 = cipb.dirInfo.ioDrMdDat - MAC_UNIX_EPOCH_DIFF;
312 buf->st_ctime = cipb.dirInfo.ioDrCrDat - MAC_UNIX_EPOCH_DIFF;
314 else
316 buf->st_mode = S_IFREG | S_IREAD;
317 if (!(cipb.hFileInfo.ioFlAttrib & 0x1))
318 buf->st_mode |= S_IWRITE; /* bit 1 = 1 for locked files/directories */
319 if (cipb.hFileInfo.ioFlFndrInfo.fdType == 'APPL')
320 buf->st_mode |= S_IEXEC;
321 buf->st_ino = cipb.hFileInfo.ioDirID;
322 buf->st_dev = cipb.hFileInfo.ioVRefNum;
323 buf->st_size = cipb.hFileInfo.ioFlLgLen;
324 buf->st_atime
325 = buf->st_mtime
326 = cipb.hFileInfo.ioFlMdDat - MAC_UNIX_EPOCH_DIFF;
327 buf->st_ctime = cipb.hFileInfo.ioFlCrDat - MAC_UNIX_EPOCH_DIFF;
330 if (cipb.hFileInfo.ioFlFndrInfo.fdFlags & 0x8000)
332 /* identify alias files as symlinks */
333 buf->st_mode &= ~S_IFREG;
334 buf->st_mode |= S_IFLNK;
337 buf->st_nlink = 1;
338 buf->st_uid = getuid ();
339 buf->st_gid = getgid ();
340 buf->st_rdev = 0;
342 return 0;
347 lstat (const char *path, struct stat *buf)
349 int result;
350 char true_pathname[MAXPATHLEN+1];
352 /* Try looking for the file without resolving aliases first. */
353 if ((result = stat_noalias (path, buf)) >= 0)
354 return result;
356 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
357 return -1;
359 return stat_noalias (true_pathname, buf);
364 stat (const char *path, struct stat *sb)
366 int result;
367 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
368 int len;
370 if ((result = stat_noalias (path, sb)) >= 0 &&
371 ! (sb->st_mode & S_IFLNK))
372 return result;
374 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
375 return -1;
377 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
378 if (len > -1)
380 fully_resolved_name[len] = '\0';
381 /* in fact our readlink terminates strings */
382 return lstat (fully_resolved_name, sb);
384 else
385 return lstat (true_pathname, sb);
389 #if __MRC__
390 /* CW defines fstat in stat.mac.c while MPW does not provide this
391 function. Without the information of how to get from a file
392 descriptor in MPW StdCLib to a Mac OS file spec, it should be hard
393 to implement this function. Fortunately, there is only one place
394 where this function is called in our configuration: in fileio.c,
395 where only the st_dev and st_ino fields are used to determine
396 whether two fildes point to different i-nodes to prevent copying
397 a file onto itself equal. What we have here probably needs
398 improvement. */
401 fstat (int fildes, struct stat *buf)
403 buf->st_dev = 0;
404 buf->st_ino = fildes;
405 buf->st_mode = S_IFREG; /* added by T.I. for the copy-file */
406 return 0; /* success */
408 #endif /* __MRC__ */
411 /* Adapted from Think Reference code example. */
414 mkdir (const char *dirname, int mode)
416 #pragma unused(mode)
418 HFileParam hfpb;
419 char true_pathname[MAXPATHLEN+1], mac_pathname[MAXPATHLEN+1];
421 if (find_true_pathname (dirname, true_pathname, MAXPATHLEN+1) == -1)
422 return -1;
424 if (posix_to_mac_pathname (true_pathname, mac_pathname, MAXPATHLEN+1) == 0)
425 return -1;
427 c2pstr (mac_pathname);
428 hfpb.ioNamePtr = mac_pathname;
429 hfpb.ioVRefNum = 0; /* ignored unless name is invalid */
430 hfpb.ioDirID = 0; /* parent is the root */
432 errno = PBDirCreate ((HParmBlkPtr) &hfpb, false);
433 /* just return the Mac OSErr code for now */
434 return errno == noErr ? 0 : -1;
438 #undef rmdir
439 sys_rmdir (const char *dirname)
441 HFileParam hfpb;
442 char mac_pathname[MAXPATHLEN+1];
444 if (posix_to_mac_pathname (dirname, mac_pathname, MAXPATHLEN+1) == 0)
445 return -1;
447 c2pstr (mac_pathname);
448 hfpb.ioNamePtr = mac_pathname;
449 hfpb.ioVRefNum = 0; /* ignored unless name is invalid */
450 hfpb.ioDirID = 0; /* parent is the root */
452 errno = PBHDelete ((HParmBlkPtr) &hfpb, false);
453 return errno == noErr ? 0 : -1;
457 #ifdef __MRC__
458 /* No implementation yet. */
460 execvp (const char *path, ...)
462 return -1;
464 #endif /* __MRC__ */
468 utime (const char *path, const struct utimbuf *times)
470 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
471 int len;
472 char mac_pathname[MAXPATHLEN+1];
473 CInfoPBRec cipb;
475 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
476 return -1;
478 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
479 if (len > -1)
480 fully_resolved_name[len] = '\0';
481 else
482 strcpy (fully_resolved_name, true_pathname);
484 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
485 return -1;
487 c2pstr (mac_pathname);
488 cipb.hFileInfo.ioNamePtr = mac_pathname;
489 cipb.hFileInfo.ioVRefNum = 0;
490 cipb.hFileInfo.ioDirID = 0;
491 cipb.hFileInfo.ioFDirIndex = 0;
492 /* set to 0 to get information about specific dir or file */
494 errno = PBGetCatInfo (&cipb, false);
495 if (errno != noErr)
496 return -1;
498 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* bit 4 = 1 for directories */
500 if (times)
501 cipb.dirInfo.ioDrMdDat = times->modtime + MAC_UNIX_EPOCH_DIFF;
502 else
503 GetDateTime (&cipb.dirInfo.ioDrMdDat);
505 else
507 if (times)
508 cipb.hFileInfo.ioFlMdDat = times->modtime + MAC_UNIX_EPOCH_DIFF;
509 else
510 GetDateTime (&cipb.hFileInfo.ioFlMdDat);
513 errno = PBSetCatInfo (&cipb, false);
514 return errno == noErr ? 0 : -1;
518 #ifndef F_OK
519 #define F_OK 0
520 #endif
521 #ifndef X_OK
522 #define X_OK 1
523 #endif
524 #ifndef W_OK
525 #define W_OK 2
526 #endif
528 /* Like stat, but test for access mode in hfpb.ioFlAttrib */
530 access (const char *path, int mode)
532 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
533 int len;
534 char mac_pathname[MAXPATHLEN+1];
535 CInfoPBRec cipb;
537 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
538 return -1;
540 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
541 if (len > -1)
542 fully_resolved_name[len] = '\0';
543 else
544 strcpy (fully_resolved_name, true_pathname);
546 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
547 return -1;
549 c2pstr (mac_pathname);
550 cipb.hFileInfo.ioNamePtr = mac_pathname;
551 cipb.hFileInfo.ioVRefNum = 0;
552 cipb.hFileInfo.ioDirID = 0;
553 cipb.hFileInfo.ioFDirIndex = 0;
554 /* set to 0 to get information about specific dir or file */
556 errno = PBGetCatInfo (&cipb, false);
557 if (errno != noErr)
558 return -1;
560 if (mode == F_OK) /* got this far, file exists */
561 return 0;
563 if (mode & X_OK)
564 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* path refers to a directory */
565 return 0;
566 else
568 if (cipb.hFileInfo.ioFlFndrInfo.fdType == 'APPL')
569 return 0;
570 else
571 return -1;
574 if (mode & W_OK)
575 return (cipb.hFileInfo.ioFlAttrib & 0x1) ? -1 : 0;
576 /* don't allow if lock bit is on */
578 return -1;
582 #define DEV_NULL_FD 0x10000
584 #undef open
586 sys_open (const char *path, int oflag)
588 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
589 int len;
590 char mac_pathname[MAXPATHLEN+1];
592 if (strcmp (path, "/dev/null") == 0)
593 return DEV_NULL_FD; /* some bogus fd to be ignored in write */
595 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
596 return -1;
598 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
599 if (len > -1)
600 fully_resolved_name[len] = '\0';
601 else
602 strcpy (fully_resolved_name, true_pathname);
604 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
605 return -1;
606 else
608 #ifdef __MRC__
609 int res = open (mac_pathname, oflag);
610 /* if (oflag == O_WRONLY || oflag == O_RDWR) */
611 if (oflag & O_CREAT)
612 fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
613 return res;
614 #else
615 return open (mac_pathname, oflag);
616 #endif
621 #undef creat
623 sys_creat (const char *path, mode_t mode)
625 char true_pathname[MAXPATHLEN+1];
626 int len;
627 char mac_pathname[MAXPATHLEN+1];
629 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
630 return -1;
632 if (!posix_to_mac_pathname (true_pathname, mac_pathname, MAXPATHLEN+1))
633 return -1;
634 else
636 #ifdef __MRC__
637 int result = creat (mac_pathname);
638 fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
639 return result;
640 #else
641 return creat (mac_pathname, mode);
642 #endif
647 #undef unlink
649 sys_unlink (const char *path)
651 char true_pathname[MAXPATHLEN+1], fully_resolved_name[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 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
659 if (len > -1)
660 fully_resolved_name[len] = '\0';
661 else
662 strcpy (fully_resolved_name, true_pathname);
664 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
665 return -1;
666 else
667 return unlink (mac_pathname);
671 #undef read
673 sys_read (int fildes, char *buf, int count)
675 if (fildes == 0) /* this should not be used for console input */
676 return -1;
677 else
678 #ifdef CODEWARRIOR_VERSION_6
679 return _read (fildes, buf, count);
680 #else
681 return read (fildes, buf, count);
682 #endif
686 #undef write
688 sys_write (int fildes, const char *buf, int count)
690 if (fildes == DEV_NULL_FD)
691 return count;
692 else
693 #ifdef CODEWARRIOR_VERSION_6
694 return _write (fildes, buf, count);
695 #else
696 return write (fildes, buf, count);
697 #endif
701 #undef rename
703 sys_rename (const char * old_name, const char * new_name)
705 char true_old_pathname[MAXPATHLEN+1], true_new_pathname[MAXPATHLEN+1];
706 char fully_resolved_old_name[MAXPATHLEN+1];
707 int len;
708 char mac_old_name[MAXPATHLEN+1], mac_new_name[MAXPATHLEN+1];
710 if (find_true_pathname (old_name, true_old_pathname, MAXPATHLEN+1) == -1)
711 return -1;
713 len = readlink (true_old_pathname, fully_resolved_old_name, MAXPATHLEN);
714 if (len > -1)
715 fully_resolved_old_name[len] = '\0';
716 else
717 strcpy (fully_resolved_old_name, true_old_pathname);
719 if (find_true_pathname (new_name, true_new_pathname, MAXPATHLEN+1) == -1)
720 return -1;
722 if (strcmp (fully_resolved_old_name, true_new_pathname) == 0)
723 return 0;
725 if (!posix_to_mac_pathname (fully_resolved_old_name,
726 mac_old_name,
727 MAXPATHLEN+1))
728 return -1;
730 if (!posix_to_mac_pathname(true_new_pathname, mac_new_name, MAXPATHLEN+1))
731 return -1;
733 /* If a file with new_name already exists, rename deletes the old
734 file in Unix. CW version fails in these situation. So we add a
735 call to unlink here. */
736 (void) unlink (mac_new_name);
738 return rename (mac_old_name, mac_new_name);
742 #undef fopen
743 extern FILE *fopen (const char *name, const char *mode);
744 FILE *
745 sys_fopen (const char *name, const char *mode)
747 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
748 int len;
749 char mac_pathname[MAXPATHLEN+1];
751 if (find_true_pathname (name, true_pathname, MAXPATHLEN+1) == -1)
752 return 0;
754 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
755 if (len > -1)
756 fully_resolved_name[len] = '\0';
757 else
758 strcpy (fully_resolved_name, true_pathname);
760 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
761 return 0;
762 else
764 #ifdef __MRC__
765 if (mode[0] == 'w' || mode[0] == 'a')
766 fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
767 #endif
768 return fopen (mac_pathname, mode);
773 #include <Events.h>
775 long target_ticks = 0;
777 #ifdef __MRC__
778 __sigfun alarm_signal_func = (__sigfun) 0;
779 #elif __MWERKS__
780 __signal_func_ptr alarm_signal_func = (__signal_func_ptr) 0;
781 #else
782 You lose!!!
783 #endif
786 /* These functions simulate SIG_ALRM. The stub for function signal
787 stores the signal handler function in alarm_signal_func if a
788 SIG_ALRM is encountered. check_alarm is called in XTread_socket,
789 which emacs calls periodically. A pending alarm is represented by
790 a non-zero target_ticks value. check_alarm calls the handler
791 function pointed to by alarm_signal_func if one has been set up and
792 an alarm is pending. */
794 void
795 check_alarm ()
797 if (target_ticks && TickCount () > target_ticks)
799 target_ticks = 0;
800 if (alarm_signal_func)
801 (*alarm_signal_func)(SIGALRM);
807 select(n, rfds, wfds, efds, timeout)
808 int n;
809 SELECT_TYPE *rfds;
810 SELECT_TYPE *wfds;
811 SELECT_TYPE *efds;
812 struct timeval *timeout;
814 EMACS_TIME end_time, now;
815 EventRecord e;
817 /* Can only handle wait for keyboard input. */
818 if (n > 1 || wfds || efds)
819 return -1;
821 EMACS_GET_TIME (end_time);
822 EMACS_ADD_TIME (end_time, end_time, *timeout);
826 /* Also return true if an event other than a keyDown has
827 occurred. This causes kbd_buffer_get_event in keyboard.c to
828 call read_avail_input which in turn calls XTread_socket to
829 poll for these events. Otherwise these never get processed
830 except but a very slow poll timer. */
831 if (FD_ISSET (0, rfds) && EventAvail (everyEvent, &e))
832 return 1;
834 /* Also check movement of the mouse. */
836 Point mouse_pos;
837 static Point old_mouse_pos = {-1, -1};
839 GetMouse (&mouse_pos);
840 if (!EqualPt (mouse_pos, old_mouse_pos))
842 old_mouse_pos = mouse_pos;
843 return 1;
847 WaitNextEvent (0, &e, 1UL, NULL); /* Accept no event; wait 1 tic. by T.I.*/
849 EMACS_GET_TIME (now);
850 EMACS_SUB_TIME (now, end_time, now);
852 while (!EMACS_TIME_NEG_P (now));
854 return 0;
858 /* Called in sys_select to wait for an alarm signal to arrive. */
861 pause ()
863 EventRecord e;
864 unsigned long tick;
866 if (!target_ticks) /* no alarm pending */
867 return -1;
869 if ( (tick = TickCount ()) < target_ticks )
870 WaitNextEvent (0, &e, target_ticks - tick, NULL); /* Accept no event; just wait. by T.I.*/
872 target_ticks = 0;
873 if (alarm_signal_func)
874 (*alarm_signal_func)(SIGALRM);
876 return 0;
881 alarm (int seconds)
883 long remaining = target_ticks ? (TickCount () - target_ticks) / 60 : 0;
885 target_ticks = seconds ? TickCount () + 60 * seconds : 0;
887 return (remaining < 0) ? 0 : (unsigned int) remaining;
891 #undef signal
892 #ifdef __MRC__
893 extern __sigfun signal (int signal, __sigfun signal_func);
894 __sigfun
895 sys_signal (int signal_num, __sigfun signal_func)
896 #elif __MWERKS__
897 extern __signal_func_ptr signal (int signal, __signal_func_ptr signal_func);
898 __signal_func_ptr
899 sys_signal (int signal_num, __signal_func_ptr signal_func)
900 #else
901 You lose!!!
902 #endif
904 if (signal_num != SIGALRM)
905 return signal (signal_num, signal_func);
906 else
908 #ifdef __MRC__
909 __sigfun old_signal_func;
910 #elif __MWERKS__
911 __signal_func_ptr old_signal_func;
912 #else
913 You lose!!!
914 #endif
915 old_signal_func = alarm_signal_func;
916 alarm_signal_func = signal_func;
917 return old_signal_func;
922 /* gettimeofday should return the amount of time (in a timeval
923 structure) since midnight today. The toolbox function Microseconds
924 returns the number of microseconds (in a UnsignedWide value) since
925 the machine was booted. Also making this complicated is WideAdd,
926 WideSubtract, etc. take wide values. */
929 gettimeofday (tp)
930 struct timeval *tp;
932 static inited = 0;
933 static wide wall_clock_at_epoch, clicks_at_epoch;
934 UnsignedWide uw_microseconds;
935 wide w_microseconds;
936 time_t sys_time (time_t *);
938 /* If this function is called for the first time, record the number
939 of seconds since midnight and the number of microseconds since
940 boot at the time of this first call. */
941 if (!inited)
943 time_t systime;
944 inited = 1;
945 systime = sys_time (NULL);
946 /* Store microseconds since midnight in wall_clock_at_epoch. */
947 WideMultiply (systime, 1000000L, &wall_clock_at_epoch);
948 Microseconds (&uw_microseconds);
949 /* Store microseconds since boot in clicks_at_epoch. */
950 clicks_at_epoch.hi = uw_microseconds.hi;
951 clicks_at_epoch.lo = uw_microseconds.lo;
954 /* Get time since boot */
955 Microseconds (&uw_microseconds);
957 /* Convert to time since midnight*/
958 w_microseconds.hi = uw_microseconds.hi;
959 w_microseconds.lo = uw_microseconds.lo;
960 WideSubtract (&w_microseconds, &clicks_at_epoch);
961 WideAdd (&w_microseconds, &wall_clock_at_epoch);
962 tp->tv_sec = WideDivide (&w_microseconds, 1000000L, &tp->tv_usec);
964 return 0;
968 #ifdef __MRC__
969 unsigned int
970 sleep (unsigned int seconds)
972 unsigned long time_up;
973 EventRecord e;
975 time_up = TickCount () + seconds * 60;
976 while (TickCount () < time_up)
978 /* Accept no event; just wait. by T.I. */
979 WaitNextEvent (0, &e, 30, NULL);
982 return (0);
984 #endif /* __MRC__ */
987 /* The time functions adjust time values according to the difference
988 between the Unix and CW epoches. */
990 #undef gmtime
991 extern struct tm *gmtime (const time_t *);
992 struct tm *
993 sys_gmtime (const time_t *timer)
995 time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
997 return gmtime (&unix_time);
1001 #undef localtime
1002 extern struct tm *localtime (const time_t *);
1003 struct tm *
1004 sys_localtime (const time_t *timer)
1006 #ifdef CODEWARRIOR_VERSION_6
1007 time_t unix_time = *timer;
1008 #else
1009 time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
1010 #endif
1012 return localtime (&unix_time);
1016 #undef ctime
1017 extern char *ctime (const time_t *);
1018 char *
1019 sys_ctime (const time_t *timer)
1021 #ifdef CODEWARRIOR_VERSION_6
1022 time_t unix_time = *timer;
1023 #else
1024 time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
1025 #endif
1027 return ctime (&unix_time);
1031 #undef time
1032 extern time_t time (time_t *);
1033 time_t
1034 sys_time (time_t *timer)
1036 #ifdef CODEWARRIOR_VERSION_6
1037 time_t mac_time = time (NULL);
1038 #else
1039 time_t mac_time = time (NULL) - CW_OR_MPW_UNIX_EPOCH_DIFF;
1040 #endif
1042 if (timer)
1043 *timer = mac_time;
1045 return mac_time;
1049 /* MPW strftime broken for "%p" format */
1050 #ifdef __MRC__
1051 #undef strftime
1052 #include <time.h>
1053 size_t
1054 sys_strftime (char * s, size_t maxsize, const char * format,
1055 const struct tm * timeptr)
1057 if (strcmp (format, "%p") == 0)
1059 if (maxsize < 3)
1060 return 0;
1061 if (timeptr->tm_hour < 12)
1063 strcpy (s, "AM");
1064 return 2;
1066 else
1068 strcpy (s, "PM");
1069 return 2;
1072 else
1073 return strftime (s, maxsize, format, timeptr);
1075 #endif /* __MRC__ */
1078 /* no subprocesses, empty wait */
1081 wait (int pid)
1083 return 0;
1087 void
1088 croak (char *badfunc)
1090 printf ("%s not yet implemented\r\n", badfunc);
1091 exit (1);
1095 char *
1096 index (const char * str, int chr)
1098 return strchr (str, chr);
1102 char *
1103 mktemp (char *template)
1105 int len, k;
1106 static seqnum = 0;
1108 len = strlen (template);
1109 k = len - 1;
1110 while (k >= 0 && template[k] == 'X')
1111 k--;
1113 k++; /* make k index of first 'X' */
1115 if (k < len)
1117 /* Zero filled, number of digits equal to the number of X's. */
1118 sprintf (&template[k], "%0*d", len-k, seqnum++);
1120 return template;
1122 else
1123 return 0;
1127 /* Emulate getpwuid, getpwnam and others. */
1129 #define PASSWD_FIELD_SIZE 256
1131 static char my_passwd_name[PASSWD_FIELD_SIZE];
1132 static char my_passwd_dir[MAXPATHLEN+1];
1134 static struct passwd my_passwd =
1136 my_passwd_name,
1137 my_passwd_dir,
1141 /* Initialized by main () in macterm.c to pathname of emacs directory. */
1143 char emacs_passwd_dir[MAXPATHLEN+1];
1145 char *
1146 getwd (char *);
1148 void
1149 init_emacs_passwd_dir ()
1151 int found = false;
1153 if (getwd (emacs_passwd_dir) && getwd (my_passwd_dir))
1155 /* Need pathname of first ancestor that begins with "emacs"
1156 since Mac emacs application is somewhere in the emacs-*
1157 tree. */
1158 int len = strlen (emacs_passwd_dir);
1159 int j = len - 1;
1160 /* j points to the "/" following the directory name being
1161 compared. */
1162 int i = j - 1;
1163 while (i >= 0 && !found)
1165 while (i >= 0 && emacs_passwd_dir[i] != '/')
1166 i--;
1167 if (emacs_passwd_dir[i] == '/' && i+5 < len)
1168 found = (strncmp (&(emacs_passwd_dir[i+1]), "emacs", 5) == 0);
1169 if (found)
1170 emacs_passwd_dir[j+1] = '\0';
1171 else
1173 j = i;
1174 i = j - 1;
1179 if (!found)
1181 /* Setting to "/" probably won't work but set it to something
1182 anyway. */
1183 strcpy (emacs_passwd_dir, "/");
1184 strcpy (my_passwd_dir, "/");
1189 static struct passwd emacs_passwd =
1191 "emacs",
1192 emacs_passwd_dir,
1195 static int my_passwd_inited = 0;
1198 static void
1199 init_my_passwd ()
1201 char **owner_name;
1203 /* Note: my_passwd_dir initialized in int_emacs_passwd_dir to
1204 directory where Emacs was started. */
1206 owner_name = (char **) GetResource ('STR ',-16096);
1207 if (owner_name)
1209 HLock (owner_name);
1210 BlockMove ((unsigned char *) *owner_name,
1211 (unsigned char *) my_passwd_name,
1212 *owner_name[0]+1);
1213 HUnlock (owner_name);
1214 p2cstr ((unsigned char *) my_passwd_name);
1216 else
1217 my_passwd_name[0] = 0;
1221 struct passwd *
1222 getpwuid (uid_t uid)
1224 if (!my_passwd_inited)
1226 init_my_passwd ();
1227 my_passwd_inited = 1;
1230 return &my_passwd;
1234 struct passwd *
1235 getpwnam (const char *name)
1237 if (strcmp (name, "emacs") == 0)
1238 return &emacs_passwd;
1240 if (!my_passwd_inited)
1242 init_my_passwd ();
1243 my_passwd_inited = 1;
1246 return &my_passwd;
1250 /* The functions fork, kill, sigsetmask, sigblock, request_sigio,
1251 setpgrp, setpriority, and unrequest_sigio are defined to be empty
1252 as in msdos.c. */
1256 fork ()
1258 return -1;
1263 kill (int x, int y)
1265 return -1;
1269 void
1270 sys_subshell ()
1272 error ("Can't spawn subshell");
1277 sigsetmask (int x)
1279 return 0;
1284 sigblock (int mask)
1286 return 0;
1290 void
1291 request_sigio (void)
1296 void
1297 unrequest_sigio (void)
1303 setpgrp ()
1305 return 0;
1309 /* No pipes yet. */
1312 pipe (int _fildes[2])
1314 errno = EACCES;
1315 return -1;
1319 /* Hard and symbolic links. */
1322 symlink (const char *name1, const char *name2)
1324 errno = ENOENT;
1325 return -1;
1330 link (const char *name1, const char *name2)
1332 errno = ENOENT;
1333 return -1;
1337 /* Determine the path name of the file specified by VREFNUM, DIRID,
1338 and NAME and place that in the buffer PATH of length
1339 MAXPATHLEN. */
1341 path_from_vol_dir_name (char *path, int man_path_len, short vol_ref_num,
1342 long dir_id, ConstStr255Param name)
1344 Str255 dir_name;
1345 CInfoPBRec cipb;
1346 OSErr err;
1348 if (strlen (name) > man_path_len)
1349 return 0;
1351 memcpy (dir_name, name, name[0]+1);
1352 memcpy (path, name, name[0]+1);
1353 p2cstr (path);
1355 cipb.dirInfo.ioDrParID = dir_id;
1356 cipb.dirInfo.ioNamePtr = dir_name;
1360 cipb.dirInfo.ioVRefNum = vol_ref_num;
1361 cipb.dirInfo.ioFDirIndex = -1;
1362 cipb.dirInfo.ioDrDirID = cipb.dirInfo.ioDrParID;
1363 /* go up to parent each time */
1365 err = PBGetCatInfo (&cipb, false);
1366 if (err != noErr)
1367 return 0;
1369 p2cstr (dir_name);
1370 if (strlen (dir_name) + strlen (path) + 1 >= man_path_len)
1371 return 0;
1373 strcat (dir_name, ":");
1374 strcat (dir_name, path);
1375 /* attach to front since we're going up directory tree */
1376 strcpy (path, dir_name);
1378 while (cipb.dirInfo.ioDrDirID != fsRtDirID);
1379 /* stop when we see the volume's root directory */
1381 return 1; /* success */
1386 readlink (const char *path, char *buf, int bufsiz)
1388 char mac_sym_link_name[MAXPATHLEN+1];
1389 OSErr err;
1390 FSSpec fsspec;
1391 Boolean target_is_folder, was_aliased;
1392 Str255 directory_name, mac_pathname;
1393 CInfoPBRec cipb;
1395 if (posix_to_mac_pathname (path, mac_sym_link_name, MAXPATHLEN+1) == 0)
1396 return -1;
1398 c2pstr (mac_sym_link_name);
1399 err = FSMakeFSSpec (0, 0, mac_sym_link_name, &fsspec);
1400 if (err != noErr)
1402 errno = ENOENT;
1403 return -1;
1406 err = ResolveAliasFile (&fsspec, true, &target_is_folder, &was_aliased);
1407 if (err != noErr || !was_aliased)
1409 errno = ENOENT;
1410 return -1;
1413 if (path_from_vol_dir_name (mac_pathname, 255, fsspec.vRefNum, fsspec.parID,
1414 fsspec.name) == 0)
1416 errno = ENOENT;
1417 return -1;
1420 if (mac_to_posix_pathname (mac_pathname, buf, bufsiz) == 0)
1422 errno = ENOENT;
1423 return -1;
1426 return strlen (buf);
1430 /* Convert a path to one with aliases fully expanded. */
1432 static int
1433 find_true_pathname (const char *path, char *buf, int bufsiz)
1435 char *q, temp[MAXPATHLEN+1];
1436 const char *p;
1437 int len;
1439 if (bufsiz <= 0 || path == 0 || path[0] == '\0')
1440 return -1;
1442 buf[0] = '\0';
1444 p = path;
1445 if (*p == '/')
1446 q = strchr (p + 1, '/');
1447 else
1448 q = strchr (p, '/');
1449 len = 0; /* loop may not be entered, e.g., for "/" */
1451 while (q)
1453 strcpy (temp, buf);
1454 strncat (temp, p, q - p);
1455 len = readlink (temp, buf, bufsiz);
1456 if (len <= -1)
1458 if (strlen (temp) + 1 > bufsiz)
1459 return -1;
1460 strcpy (buf, temp);
1462 strcat (buf, "/");
1463 len++;
1464 p = q + 1;
1465 q = strchr(p, '/');
1468 if (len + strlen (p) + 1 >= bufsiz)
1469 return -1;
1471 strcat (buf, p);
1472 return len + strlen (p);
1476 mode_t
1477 umask (mode_t numask)
1479 static mode_t mask = 022;
1480 mode_t oldmask = mask;
1481 mask = numask;
1482 return oldmask;
1487 chmod (const char *path, mode_t mode)
1489 /* say it always succeed for now */
1490 return 0;
1495 dup (int oldd)
1497 #ifdef __MRC__
1498 return fcntl (oldd, F_DUPFD, 0);
1499 #elif __MWERKS__
1500 /* current implementation of fcntl in fcntl.mac.c simply returns old
1501 descriptor */
1502 return fcntl (oldd, F_DUPFD);
1503 #else
1504 You lose!!!
1505 #endif
1509 /* This is from the original sysdep.c. Emulate BSD dup2. First close
1510 newd if it already exists. Then, attempt to dup oldd. If not
1511 successful, call dup2 recursively until we are, then close the
1512 unsuccessful ones. */
1515 dup2 (int oldd, int newd)
1517 int fd, ret;
1519 close (newd);
1521 fd = dup (oldd);
1522 if (fd == -1)
1523 return -1;
1524 if (fd == newd)
1525 return newd;
1526 ret = dup2 (oldd, newd);
1527 close (fd);
1528 return ret;
1532 /* let it fail for now */
1534 char *
1535 sbrk (int incr)
1537 return (char *) -1;
1542 fsync (int fd)
1544 return 0;
1549 ioctl (int d, int request, void *argp)
1551 return -1;
1555 #ifdef __MRC__
1557 isatty (int fildes)
1559 if (fildes >=0 && fildes <= 2)
1560 return 1;
1561 else
1562 return 0;
1567 getgid ()
1569 return 100;
1574 getegid ()
1576 return 100;
1581 getuid ()
1583 return 200;
1588 geteuid ()
1590 return 200;
1592 #endif /* __MRC__ */
1595 #ifdef __MWERKS__
1596 #ifndef CODEWARRIOR_VERSION_6
1597 #undef getpid
1599 getpid ()
1601 return 9999;
1603 #endif
1604 #endif /* __MWERKS__ */
1607 /* Return the path to the directory in which Emacs can create
1608 temporary files. The MacOS "temporary items" directory cannot be
1609 used because it removes the file written by a process when it
1610 exits. In that sense it's more like "/dev/null" than "/tmp" (but
1611 again not exactly). And of course Emacs needs to read back the
1612 files written by its subprocesses. So here we write the files to a
1613 directory "Emacs" in the Preferences Folder. This directory is
1614 created if it does not exist. */
1616 static char *
1617 get_temp_dir_name ()
1619 static char *temp_dir_name = NULL;
1620 short vol_ref_num;
1621 long dir_id;
1622 OSErr err;
1623 Str255 dir_name, full_path;
1624 CInfoPBRec cpb;
1625 char unix_dir_name[MAXPATHLEN+1];
1626 DIR *dir;
1628 /* Cache directory name with pointer temp_dir_name.
1629 Look for it only the first time. */
1630 if (!temp_dir_name)
1632 err = FindFolder (kOnSystemDisk, kPreferencesFolderType, kCreateFolder,
1633 &vol_ref_num, &dir_id);
1634 if (err != noErr)
1635 return NULL;
1637 if (!path_from_vol_dir_name (full_path, 255, vol_ref_num, dir_id, "\p"))
1638 return NULL;
1640 if (strlen (full_path) + 6 <= MAXPATHLEN)
1641 strcat (full_path, "Emacs:");
1642 else
1643 return NULL;
1645 if (!mac_to_posix_pathname (full_path, unix_dir_name, MAXPATHLEN+1))
1646 return NULL;
1648 dir = opendir (unix_dir_name); /* check whether temp directory exists */
1649 if (dir)
1650 closedir (dir);
1651 else if (mkdir (unix_dir_name, 0700) != 0) /* create it if not */
1652 return NULL;
1654 temp_dir_name = (char *) malloc (strlen (unix_dir_name) + 1);
1655 strcpy (temp_dir_name, unix_dir_name);
1658 return temp_dir_name;
1662 /* Allocate and construct an array of pointers to strings from a list
1663 of strings stored in a 'STR#' resource. The returned pointer array
1664 is stored in the style of argv and environ: if the 'STR#' resource
1665 contains numString strings, an pointer array with numString+1
1666 elements is returned in which the last entry contains a null
1667 pointer. The pointer to the pointer array is passed by pointer in
1668 parameter t. The resource ID of the 'STR#' resource is passed in
1669 parameter StringListID.
1672 void
1673 get_string_list (char ***t, short string_list_id)
1675 Handle h;
1676 Ptr p;
1677 int i, num_strings;
1679 h = GetResource ('STR#', string_list_id);
1680 if (h)
1682 HLock (h);
1683 p = *h;
1684 num_strings = * (short *) p;
1685 p += sizeof(short);
1686 *t = (char **) malloc (sizeof (char *) * (num_strings + 1));
1687 for (i = 0; i < num_strings; i++)
1689 short length = *p++;
1690 (*t)[i] = (char *) malloc (length + 1);
1691 strncpy ((*t)[i], p, length);
1692 (*t)[i][length] = '\0';
1693 p += length;
1695 (*t)[num_strings] = 0;
1696 HUnlock (h);
1698 else
1700 /* Return no string in case GetResource fails. Bug fixed by
1701 Ikegami Tsutomu. Caused MPW build to crash without sym -on
1702 option (no sym -on implies -opt local). */
1703 *t = (char **) malloc (sizeof (char *));
1704 (*t)[0] = 0;
1709 static char *
1710 get_path_to_system_folder ()
1712 short vol_ref_num;
1713 long dir_id;
1714 OSErr err;
1715 Str255 dir_name, full_path;
1716 CInfoPBRec cpb;
1717 static char system_folder_unix_name[MAXPATHLEN+1];
1718 DIR *dir;
1720 err = FindFolder (kOnSystemDisk, kSystemFolderType, kDontCreateFolder,
1721 &vol_ref_num, &dir_id);
1722 if (err != noErr)
1723 return NULL;
1725 if (!path_from_vol_dir_name (full_path, 255, vol_ref_num, dir_id, "\p"))
1726 return NULL;
1728 if (!mac_to_posix_pathname (full_path, system_folder_unix_name, MAXPATHLEN+1))
1729 return NULL;
1731 return system_folder_unix_name;
1735 char **environ;
1737 #define ENVIRON_STRING_LIST_ID 128
1739 /* Get environment variable definitions from STR# resource. */
1741 void
1742 init_environ ()
1744 int i;
1746 get_string_list (&environ, ENVIRON_STRING_LIST_ID);
1748 i = 0;
1749 while (environ[i])
1750 i++;
1752 /* Make HOME directory the one Emacs starts up in if not specified
1753 by resource. */
1754 if (getenv ("HOME") == NULL)
1756 environ = (char **) realloc (environ, sizeof (char *) * (i + 2));
1757 if (environ)
1759 environ[i] = (char *) malloc (strlen (my_passwd_dir) + 6);
1760 if (environ[i])
1762 strcpy (environ[i], "HOME=");
1763 strcat (environ[i], my_passwd_dir);
1765 environ[i+1] = 0;
1766 i++;
1770 /* Make HOME directory the one Emacs starts up in if not specified
1771 by resource. */
1772 if (getenv ("MAIL") == NULL)
1774 environ = (char **) realloc (environ, sizeof (char *) * (i + 2));
1775 if (environ)
1777 char * path_to_system_folder = get_path_to_system_folder ();
1778 environ[i] = (char *) malloc (strlen (path_to_system_folder) + 22);
1779 if (environ[i])
1781 strcpy (environ[i], "MAIL=");
1782 strcat (environ[i], path_to_system_folder);
1783 strcat (environ[i], "Eudora Folder/In");
1785 environ[i+1] = 0;
1791 /* Return the value of the environment variable NAME. */
1793 char *
1794 getenv (const char *name)
1796 int length = strlen(name);
1797 char **e;
1799 for (e = environ; *e != 0; e++)
1800 if (strncmp(*e, name, length) == 0 && (*e)[length] == '=')
1801 return &(*e)[length + 1];
1803 if (strcmp (name, "TMPDIR") == 0)
1804 return get_temp_dir_name ();
1806 return 0;
1810 #ifdef __MRC__
1811 /* see Interfaces&Libraries:Interfaces:CIncludes:signal.h */
1812 char *sys_siglist[] =
1814 "Zero is not a signal!!!",
1815 "Abort", /* 1 */
1816 "Interactive user interrupt", /* 2 */ "?",
1817 "Floating point exception", /* 4 */ "?", "?", "?",
1818 "Illegal instruction", /* 8 */ "?", "?", "?", "?", "?", "?", "?",
1819 "Segment violation", /* 16 */ "?", "?", "?", "?", "?", "?", "?",
1820 "?", "?", "?", "?", "?", "?", "?", "?",
1821 "Terminal" /* 32 */
1823 #elif __MWERKS__
1824 char *sys_siglist[] =
1826 "Zero is not a signal!!!",
1827 "Abort",
1828 "Floating point exception",
1829 "Illegal instruction",
1830 "Interactive user interrupt",
1831 "Segment violation",
1832 "Terminal"
1834 #else
1835 You lose!!!
1836 #endif
1839 #include <utsname.h>
1842 uname (struct utsname *name)
1844 char **system_name;
1845 system_name = GetString (-16413); /* IM - Resource Manager Reference */
1846 if (system_name)
1848 BlockMove (*system_name, name->nodename, (*system_name)[0]+1);
1849 p2cstr (name->nodename);
1850 return 0;
1852 else
1853 return -1;
1857 #include <Processes.h>
1858 #include <EPPC.h>
1860 /* Event class of HLE sent to subprocess. */
1861 const OSType kEmacsSubprocessSend = 'ESND';
1863 /* Event class of HLE sent back from subprocess. */
1864 const OSType kEmacsSubprocessReply = 'ERPY';
1867 char *
1868 mystrchr (char *s, char c)
1870 while (*s && *s != c)
1872 if (*s == '\\')
1873 s++;
1874 s++;
1877 if (*s)
1879 *s = '\0';
1880 return s;
1882 else
1883 return NULL;
1887 char *
1888 mystrtok (char *s)
1890 while (*s)
1891 s++;
1893 return s + 1;
1897 void
1898 mystrcpy (char *to, char *from)
1900 while (*from)
1902 if (*from == '\\')
1903 from++;
1904 *to++ = *from++;
1906 *to = '\0';
1910 /* Start a Mac subprocess. Arguments for it is passed in argv (null
1911 terminated). The process should run with the default directory
1912 "workdir", read input from "infn", and write output and error to
1913 "outfn" and "errfn", resp. The Process Manager call
1914 LaunchApplication is used to start the subprocess. We use high
1915 level events as the mechanism to pass arguments to the subprocess
1916 and to make Emacs wait for the subprocess to terminate and pass
1917 back a result code. The bulk of the code here packs the arguments
1918 into one message to be passed together with the high level event.
1919 Emacs also sometimes starts a subprocess using a shell to perform
1920 wildcard filename expansion. Since we don't really have a shell on
1921 the Mac, this case is detected and the starting of the shell is
1922 by-passed. We really need to add code here to do filename
1923 expansion to support such functionality. */
1926 run_mac_command (argv, workdir, infn, outfn, errfn)
1927 unsigned char **argv;
1928 const char *workdir;
1929 const char *infn, *outfn, *errfn;
1931 char macappname[MAXPATHLEN+1], macworkdir[MAXPATHLEN+1];
1932 char macinfn[MAXPATHLEN+1], macoutfn[MAXPATHLEN+1], macerrfn[MAXPATHLEN+1];
1933 int paramlen, argc, newargc, j, retries;
1934 char **newargv, *param, *p;
1935 OSErr iErr;
1936 FSSpec spec;
1937 LaunchParamBlockRec lpbr;
1938 EventRecord send_event, reply_event;
1939 RgnHandle cursor_region_handle;
1940 TargetID targ;
1941 unsigned long ref_con, len;
1943 if (posix_to_mac_pathname (workdir, macworkdir, MAXPATHLEN+1) == 0)
1944 return -1;
1945 if (posix_to_mac_pathname (infn, macinfn, MAXPATHLEN+1) == 0)
1946 return -1;
1947 if (posix_to_mac_pathname (outfn, macoutfn, MAXPATHLEN+1) == 0)
1948 return -1;
1949 if (posix_to_mac_pathname (errfn, macerrfn, MAXPATHLEN+1) == 0)
1950 return -1;
1952 paramlen = strlen (macworkdir) + strlen (macinfn) + strlen (macoutfn)
1953 + strlen (macerrfn) + 4; /* count nulls at end of strings */
1955 argc = 0;
1956 while (argv[argc])
1957 argc++;
1959 if (argc == 0)
1960 return -1;
1962 /* If a subprocess is invoked with a shell, we receive 3 arguments
1963 of the form: "<path to emacs bins>/sh" "-c" "<path to emacs
1964 bins>/<command> <command args>" */
1965 j = strlen (argv[0]);
1966 if (j >= 3 && strcmp (argv[0]+j-3, "/sh") == 0
1967 && argc == 3 && strcmp (argv[1], "-c") == 0)
1969 char *command, *t, tempmacpathname[MAXPATHLEN+1];
1971 /* The arguments for the command in argv[2] are separated by
1972 spaces. Count them and put the count in newargc. */
1973 command = (char *) alloca (strlen (argv[2])+2);
1974 strcpy (command, argv[2]);
1975 if (command[strlen (command) - 1] != ' ')
1976 strcat (command, " ");
1978 t = command;
1979 newargc = 0;
1980 t = mystrchr (t, ' ');
1981 while (t)
1983 newargc++;
1984 t = mystrchr (t+1, ' ');
1987 newargv = (char **) alloca (sizeof (char *) * newargc);
1989 t = command;
1990 for (j = 0; j < newargc; j++)
1992 newargv[j] = (char *) alloca (strlen (t) + 1);
1993 mystrcpy (newargv[j], t);
1995 t = mystrtok (t);
1996 paramlen += strlen (newargv[j]) + 1;
1999 if (strncmp (newargv[0], "~emacs/", 7) == 0)
2001 if (posix_to_mac_pathname (newargv[0], tempmacpathname, MAXPATHLEN+1)
2002 == 0)
2003 return -1;
2005 else
2006 { /* sometimes Emacs call "sh" without a path for the command */
2007 #if 0
2008 char *t = (char *) alloca (strlen (newargv[0]) + 7 + 1);
2009 strcpy (t, "~emacs/");
2010 strcat (t, newargv[0]);
2011 #endif
2012 Lisp_Object path;
2013 openp (Vexec_path, build_string (newargv[0]), Vexec_suffixes, &path,
2016 if (NILP (path))
2017 return -1;
2018 if (posix_to_mac_pathname (XSTRING (path)->data, tempmacpathname,
2019 MAXPATHLEN+1) == 0)
2020 return -1;
2022 strcpy (macappname, tempmacpathname);
2024 else
2026 if (posix_to_mac_pathname (argv[0], macappname, MAXPATHLEN+1) == 0)
2027 return -1;
2029 newargv = (char **) alloca (sizeof (char *) * argc);
2030 newargc = argc;
2031 for (j = 1; j < argc; j++)
2033 if (strncmp (argv[j], "~emacs/", 7) == 0)
2035 char *t = strchr (argv[j], ' ');
2036 if (t)
2038 char tempcmdname[MAXPATHLEN+1], tempmaccmdname[MAXPATHLEN+1];
2039 strncpy (tempcmdname, argv[j], t-argv[j]);
2040 tempcmdname[t-argv[j]] = '\0';
2041 if (posix_to_mac_pathname (tempcmdname, tempmaccmdname,
2042 MAXPATHLEN+1) == 0)
2043 return -1;
2044 newargv[j] = (char *) alloca (strlen (tempmaccmdname)
2045 + strlen (t) + 1);
2046 strcpy (newargv[j], tempmaccmdname);
2047 strcat (newargv[j], t);
2049 else
2051 char tempmaccmdname[MAXPATHLEN+1];
2052 if (posix_to_mac_pathname (argv[j], tempmaccmdname,
2053 MAXPATHLEN+1) == 0)
2054 return -1;
2055 newargv[j] = (char *) alloca (strlen (tempmaccmdname)+1);
2056 strcpy (newargv[j], tempmaccmdname);
2059 else
2060 newargv[j] = argv[j];
2061 paramlen += strlen (newargv[j]) + 1;
2065 /* After expanding all the arguments, we now know the length of the
2066 parameter block to be sent to the subprocess as a message
2067 attached to the HLE. */
2068 param = (char *) malloc (paramlen + 1);
2069 if (!param)
2070 return -1;
2072 p = param;
2073 *p++ = newargc;
2074 /* first byte of message contains number of arguments for command */
2075 strcpy (p, macworkdir);
2076 p += strlen (macworkdir);
2077 *p++ = '\0';
2078 /* null terminate strings sent so it's possible to use strcpy over there */
2079 strcpy (p, macinfn);
2080 p += strlen (macinfn);
2081 *p++ = '\0';
2082 strcpy (p, macoutfn);
2083 p += strlen (macoutfn);
2084 *p++ = '\0';
2085 strcpy (p, macerrfn);
2086 p += strlen (macerrfn);
2087 *p++ = '\0';
2088 for (j = 1; j < newargc; j++)
2090 strcpy (p, newargv[j]);
2091 p += strlen (newargv[j]);
2092 *p++ = '\0';
2095 c2pstr (macappname);
2097 iErr = FSMakeFSSpec (0, 0, macappname, &spec);
2099 if (iErr != noErr)
2101 free (param);
2102 return -1;
2105 lpbr.launchBlockID = extendedBlock;
2106 lpbr.launchEPBLength = extendedBlockLen;
2107 lpbr.launchControlFlags = launchContinue + launchNoFileFlags;
2108 lpbr.launchAppSpec = &spec;
2109 lpbr.launchAppParameters = NULL;
2111 iErr = LaunchApplication (&lpbr); /* call the subprocess */
2112 if (iErr != noErr)
2114 free (param);
2115 return -1;
2118 send_event.what = kHighLevelEvent;
2119 send_event.message = kEmacsSubprocessSend;
2120 /* Event ID stored in "where" unused */
2122 retries = 3;
2123 /* OS may think current subprocess has terminated if previous one
2124 terminated recently. */
2127 iErr = PostHighLevelEvent (&send_event, &lpbr.launchProcessSN, 0, param,
2128 paramlen + 1, receiverIDisPSN);
2130 while (iErr == sessClosedErr && retries-- > 0);
2132 if (iErr != noErr)
2134 free (param);
2135 return -1;
2138 cursor_region_handle = NewRgn ();
2140 /* Wait for the subprocess to finish, when it will send us a ERPY
2141 high level event. */
2142 while (1)
2143 if (WaitNextEvent (highLevelEventMask, &reply_event, 180,
2144 cursor_region_handle)
2145 && reply_event.message == kEmacsSubprocessReply)
2146 break;
2148 /* The return code is sent through the refCon */
2149 iErr = AcceptHighLevelEvent (&targ, &ref_con, NULL, &len);
2150 if (iErr != noErr)
2152 DisposeHandle ((Handle) cursor_region_handle);
2153 free (param);
2154 return -1;
2157 DisposeHandle ((Handle) cursor_region_handle);
2158 free (param);
2160 return ref_con;
2164 DIR *
2165 opendir (const char *dirname)
2167 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
2168 char mac_pathname[MAXPATHLEN+1], vol_name[MAXPATHLEN+1];
2169 DIR *dirp;
2170 CInfoPBRec cipb;
2171 HVolumeParam vpb;
2172 int len, vol_name_len;
2174 if (find_true_pathname (dirname, true_pathname, MAXPATHLEN+1) == -1)
2175 return 0;
2177 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
2178 if (len > -1)
2179 fully_resolved_name[len] = '\0';
2180 else
2181 strcpy (fully_resolved_name, true_pathname);
2183 dirp = (DIR *) malloc (sizeof(DIR));
2184 if (!dirp)
2185 return 0;
2187 /* Handle special case when dirname is "/": sets up for readir to
2188 get all mount volumes. */
2189 if (strcmp (fully_resolved_name, "/") == 0)
2191 dirp->getting_volumes = 1; /* special all mounted volumes DIR struct */
2192 dirp->current_index = 1; /* index for first volume */
2193 return dirp;
2196 /* Handle typical cases: not accessing all mounted volumes. */
2197 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
2198 return 0;
2200 /* Emacs calls opendir without the trailing '/', Mac needs trailing ':' */
2201 len = strlen (mac_pathname);
2202 if (mac_pathname[len - 1] != ':' && len < MAXPATHLEN)
2203 strcat (mac_pathname, ":");
2205 /* Extract volume name */
2206 vol_name_len = strchr (mac_pathname, ':') - mac_pathname;
2207 strncpy (vol_name, mac_pathname, vol_name_len);
2208 vol_name[vol_name_len] = '\0';
2209 strcat (vol_name, ":");
2211 c2pstr (mac_pathname);
2212 cipb.hFileInfo.ioNamePtr = mac_pathname;
2213 /* using full pathname so vRefNum and DirID ignored */
2214 cipb.hFileInfo.ioVRefNum = 0;
2215 cipb.hFileInfo.ioDirID = 0;
2216 cipb.hFileInfo.ioFDirIndex = 0;
2217 /* set to 0 to get information about specific dir or file */
2219 errno = PBGetCatInfo (&cipb, false);
2220 if (errno != noErr)
2222 errno = ENOENT;
2223 return 0;
2226 if (!(cipb.hFileInfo.ioFlAttrib & 0x10)) /* bit 4 = 1 for directories */
2227 return 0; /* not a directory */
2229 dirp->dir_id = cipb.dirInfo.ioDrDirID; /* used later in readdir */
2230 dirp->getting_volumes = 0;
2231 dirp->current_index = 1; /* index for first file/directory */
2233 c2pstr (vol_name);
2234 vpb.ioNamePtr = vol_name;
2235 /* using full pathname so vRefNum and DirID ignored */
2236 vpb.ioVRefNum = 0;
2237 vpb.ioVolIndex = -1;
2238 errno = PBHGetVInfo ((union HParamBlockRec *) &vpb, false);
2239 if (errno != noErr)
2241 errno = ENOENT;
2242 return 0;
2245 dirp->vol_ref_num = vpb.ioVRefNum;
2247 return dirp;
2251 closedir (DIR *dp)
2253 free (dp);
2255 return 0;
2259 struct dirent *
2260 readdir (DIR *dp)
2262 HParamBlockRec hpblock;
2263 CInfoPBRec cipb;
2264 static struct dirent s_dirent;
2265 static Str255 s_name;
2266 int done;
2267 char *p;
2269 /* Handle the root directory containing the mounted volumes. Call
2270 PBHGetVInfo specifying an index to obtain the info for a volume.
2271 PBHGetVInfo returns an error when it receives an index beyond the
2272 last volume, at which time we should return a nil dirent struct
2273 pointer. */
2274 if (dp->getting_volumes)
2276 hpblock.volumeParam.ioNamePtr = s_name;
2277 hpblock.volumeParam.ioVRefNum = 0;
2278 hpblock.volumeParam.ioVolIndex = dp->current_index;
2280 errno = PBHGetVInfo (&hpblock, false);
2281 if (errno != noErr)
2283 errno = ENOENT;
2284 return 0;
2287 p2cstr (s_name);
2288 strcat (s_name, "/"); /* need "/" for stat to work correctly */
2290 dp->current_index++;
2292 s_dirent.d_ino = hpblock.volumeParam.ioVRefNum;
2293 s_dirent.d_name = s_name;
2295 return &s_dirent;
2297 else
2299 cipb.hFileInfo.ioVRefNum = dp->vol_ref_num;
2300 cipb.hFileInfo.ioNamePtr = s_name;
2301 /* location to receive filename returned */
2303 /* return only visible files */
2304 done = false;
2305 while (!done)
2307 cipb.hFileInfo.ioDirID = dp->dir_id;
2308 /* directory ID found by opendir */
2309 cipb.hFileInfo.ioFDirIndex = dp->current_index;
2311 errno = PBGetCatInfo (&cipb, false);
2312 if (errno != noErr)
2314 errno = ENOENT;
2315 return 0;
2318 /* insist on an visibile entry */
2319 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* directory? */
2320 done = !(cipb.dirInfo.ioDrUsrWds.frFlags & fInvisible);
2321 else
2322 done = !(cipb.hFileInfo.ioFlFndrInfo.fdFlags & fInvisible);
2324 dp->current_index++;
2327 p2cstr (s_name);
2329 p = s_name;
2330 while (*p)
2332 if (*p == '/')
2333 *p = ':';
2334 p++;
2337 s_dirent.d_ino = cipb.dirInfo.ioDrDirID;
2338 /* value unimportant: non-zero for valid file */
2339 s_dirent.d_name = s_name;
2341 return &s_dirent;
2346 char *
2347 getwd (char *path)
2349 char mac_pathname[MAXPATHLEN+1];
2350 Str255 directory_name;
2351 OSErr errno;
2352 CInfoPBRec cipb;
2354 if (path_from_vol_dir_name (mac_pathname, 255, 0, 0, "\p") == 0)
2355 return NULL;
2357 if (mac_to_posix_pathname (mac_pathname, path, MAXPATHLEN+1) == 0)
2358 return 0;
2359 else
2360 return path;
2364 void
2365 initialize_applescript ()
2367 AEDesc null_desc;
2368 OSAError osaerror;
2370 /* if open fails, as_scripting_component is set to NULL. Its
2371 subsequent use in OSA calls will fail with badComponentInstance
2372 error. */
2373 as_scripting_component = OpenDefaultComponent (kOSAComponentType,
2374 kAppleScriptSubtype);
2376 null_desc.descriptorType = typeNull;
2377 null_desc.dataHandle = 0;
2378 osaerror = OSAMakeContext (as_scripting_component, &null_desc,
2379 kOSANullScript, &as_script_context);
2380 if (osaerror)
2381 as_script_context = kOSANullScript;
2382 /* use default context if create fails */
2386 void terminate_applescript()
2388 OSADispose (as_scripting_component, as_script_context);
2389 CloseComponent (as_scripting_component);
2393 /* Compile and execute the AppleScript SCRIPT and return the error
2394 status as function value. A zero is returned if compilation and
2395 execution is successful, in which case RESULT returns a pointer to
2396 a string containing the resulting script value. Otherwise, the Mac
2397 error code is returned and RESULT returns a pointer to an error
2398 string. In both cases the caller should deallocate the storage
2399 used by the string pointed to by RESULT if it is non-NULL. For
2400 documentation on the MacOS scripting architecture, see Inside
2401 Macintosh - Interapplication Communications: Scripting Components. */
2403 static long
2404 do_applescript (char *script, char **result)
2406 AEDesc script_desc, result_desc, error_desc;
2407 OSErr error;
2408 OSAError osaerror;
2409 long length;
2411 *result = 0;
2413 error = AECreateDesc (typeChar, script, strlen(script), &script_desc);
2414 if (error)
2415 return error;
2417 osaerror = OSADoScript (as_scripting_component, &script_desc, kOSANullScript,
2418 typeChar, kOSAModeNull, &result_desc);
2420 if (osaerror == errOSAScriptError)
2422 /* error executing AppleScript: retrieve error message */
2423 if (!OSAScriptError (as_scripting_component, kOSAErrorMessage, typeChar,
2424 &error_desc))
2426 HLock (error_desc.dataHandle);
2427 length = GetHandleSize(error_desc.dataHandle);
2428 *result = (char *) xmalloc (length + 1);
2429 if (*result)
2431 memcpy (*result, *(error_desc.dataHandle), length);
2432 *(*result + length) = '\0';
2434 HUnlock (error_desc.dataHandle);
2435 AEDisposeDesc (&error_desc);
2438 else if (osaerror == noErr) /* success: retrieve resulting script value */
2440 HLock (result_desc.dataHandle);
2441 length = GetHandleSize(result_desc.dataHandle);
2442 *result = (char *) xmalloc (length + 1);
2443 if (*result)
2445 memcpy (*result, *(result_desc.dataHandle), length);
2446 *(*result + length) = '\0';
2448 HUnlock (result_desc.dataHandle);
2451 AEDisposeDesc (&script_desc);
2452 AEDisposeDesc (&result_desc);
2454 return osaerror;
2458 DEFUN ("do-applescript", Fdo_applescript, Sdo_applescript, 1, 1, 0,
2459 "Compile and execute AppleScript SCRIPT and retrieve and return the\n\
2460 result. If compilation and execution are successful, the resulting script\n\
2461 value is returned as a string. Otherwise the function aborts and\n\
2462 displays the error message returned by the AppleScript scripting\n\
2463 component.")
2464 (script)
2465 Lisp_Object script;
2467 char *result, *temp;
2468 Lisp_Object lisp_result;
2469 long status;
2471 CHECK_STRING (script, 0);
2473 status = do_applescript (XSTRING (script)->data, &result);
2474 if (status)
2476 if (!result)
2477 error ("AppleScript error %ld", status);
2478 else
2480 /* Unfortunately only OSADoScript in do_applescript knows how
2481 how large the resulting script value or error message is
2482 going to be and therefore as caller memory must be
2483 deallocated here. It is necessary to free the error
2484 message before calling error to avoid a memory leak. */
2485 temp = (char *) alloca (strlen (result) + 1);
2486 strcpy (temp, result);
2487 xfree (result);
2488 error (temp);
2491 else
2493 lisp_result = build_string (result);
2494 xfree (result);
2495 return lisp_result;
2500 DEFUN ("mac-file-name-to-posix", Fmac_file_name_to_posix, Smac_file_name_to_posix, 1,
2501 1, 0,
2502 "Convert Macintosh filename to Posix form.")
2503 (mac_filename)
2504 Lisp_Object mac_filename;
2506 char posix_filename[MAXPATHLEN+1];
2508 CHECK_STRING (mac_filename, 0);
2510 if (mac_to_posix_pathname (XSTRING (mac_filename)->data, posix_filename,
2511 MAXPATHLEN))
2512 return build_string (posix_filename);
2513 else
2514 return Qnil;
2518 DEFUN ("posix-file-name-to-mac", Fposix_file_name_to_mac, Sposix_file_name_to_mac, 1,
2519 1, 0,
2520 "Convert Unix filename to Mac form.")
2521 (posix_filename)
2522 Lisp_Object posix_filename;
2524 char mac_filename[MAXPATHLEN+1];
2526 CHECK_STRING (posix_filename, 0);
2528 if (posix_to_mac_pathname (XSTRING (posix_filename)->data, mac_filename,
2529 MAXPATHLEN))
2530 return build_string (mac_filename);
2531 else
2532 return Qnil;
2536 /* set interprogram-paste-function to mac-paste-function in mac-win.el
2537 to enable Emacs to obtain the contents of the Mac clipboard. */
2538 DEFUN ("mac-paste-function", Fmac_paste_function, Smac_paste_function, 0, 0, 0,
2539 "Return the contents of the Mac clipboard as a string.")
2542 Lisp_Object value;
2543 Handle my_handle;
2544 long scrap_offset, rc, i;
2546 my_handle = NewHandle (0); /* allocate 0-length data area */
2548 rc = GetScrap (my_handle, 'TEXT', &scrap_offset);
2549 if (rc < 0)
2550 return Qnil;
2552 HLock (my_handle);
2554 /* Emacs expects clipboard contents have Unix-style eol's */
2555 for (i = 0; i < rc; i++)
2556 if ((*my_handle)[i] == '\r')
2557 (*my_handle)[i] = '\n';
2559 value = make_string (*my_handle, rc);
2561 HUnlock (my_handle);
2563 DisposeHandle (my_handle);
2565 return value;
2569 /* set interprogram-cut-function to mac-cut-function in mac-win.el
2570 to enable Emacs to write the top of the kill-ring to the Mac clipboard. */
2571 DEFUN ("mac-cut-function", Fmac_cut_function, Smac_cut_function, 1, 2, 0,
2572 "Put the value of the string parameter to the Mac clipboard.")
2573 (value, push)
2574 Lisp_Object value, push;
2576 char *buf;
2577 int len, i;
2579 /* fixme: ignore the push flag for now */
2581 CHECK_STRING (value, 0);
2583 len = XSTRING (value)->size;
2584 buf = (char *) alloca (len);
2585 bcopy(XSTRING (value)->data, buf, len);
2587 /* convert to Mac-style eol's before sending to clipboard */
2588 for (i = 0; i < len; i++)
2589 if (buf[i] == '\n')
2590 buf[i] = '\r';
2592 ZeroScrap ();
2593 PutScrap (len, 'TEXT', buf);
2595 return Qnil;
2599 DEFUN ("x-selection-exists-p", Fx_selection_exists_p, Sx_selection_exists_p,
2600 0, 1, 0,
2601 "Whether there is an owner for the given X Selection.\n\
2602 The arg should be the name of the selection in question, typically one of\n\
2603 the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.\n\
2604 \(Those are literal upper-case symbol names, since that's what X expects.)\n\
2605 For convenience, the symbol nil is the same as `PRIMARY',\n\
2606 and t is the same as `SECONDARY'.")
2607 (selection)
2608 Lisp_Object selection;
2610 CHECK_SYMBOL (selection, 0);
2612 /* Return nil for PRIMARY and SECONDARY selections; for CLIPBOARD, check
2613 if the clipboard currently has valid text format contents. */
2615 if (EQ (selection, QCLIPBOARD))
2617 Lisp_Object val = Qnil;
2618 Lisp_Object value;
2619 Handle my_handle;
2620 long rc, scrap_offset;
2622 my_handle = NewHandle (0);
2624 rc = GetScrap (my_handle, 'TEXT', &scrap_offset);
2625 if (rc >= 0)
2626 val = Qt;
2628 DisposeHandle (my_handle);
2630 return val;
2632 return Qnil;
2636 void
2637 syms_of_mac ()
2639 QCLIPBOARD = intern ("CLIPBOARD");
2640 staticpro (&QCLIPBOARD);
2642 defsubr (&Smac_paste_function);
2643 defsubr (&Smac_cut_function);
2644 defsubr (&Sx_selection_exists_p);
2646 defsubr (&Sdo_applescript);
2647 defsubr (&Smac_file_name_to_posix);
2648 defsubr (&Sposix_file_name_to_mac);