(cp1125): New.
[emacs.git] / mac / src / mac.c
blob08d2aa2d8bbb0998c650f00b8e14ccd6a76e0179
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_unix_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 unix_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 (unix_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_IFLNK;
334 buf->st_mode &= ~S_IFREG;
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 return result;
373 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
374 return -1;
376 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
377 if (len > -1)
379 fully_resolved_name[len] = '\0';
380 /* in fact our readlink terminates strings */
381 return lstat (fully_resolved_name, sb);
383 else
384 return lstat (true_pathname, sb);
388 #if __MRC__
389 /* CW defines fstat in stat.mac.c while MPW does not provide this
390 function. Without the information of how to get from a file
391 descriptor in MPW StdCLib to a Mac OS file spec, it should be hard
392 to implement this function. Fortunately, there is only one place
393 where this function is called in our configuration: in fileio.c,
394 where only the st_dev and st_ino fields are used to determine
395 whether two fildes point to different i-nodes to prevent copying
396 a file onto itself equal. What we have here probably needs
397 improvement. */
400 fstat (int fildes, struct stat *buf)
402 buf->st_dev = 0;
403 buf->st_ino = fildes;
404 buf->st_mode = S_IFREG; /* added by T.I. for the copy-file */
405 return 0; /* success */
407 #endif /* __MRC__ */
410 /* Adapted from Think Reference code example. */
413 mkdir (const char *dirname, int mode)
415 #pragma unused(mode)
417 HFileParam hfpb;
418 char true_pathname[MAXPATHLEN+1], mac_pathname[MAXPATHLEN+1];
420 if (find_true_pathname (dirname, true_pathname, MAXPATHLEN+1) == -1)
421 return -1;
423 if (unix_to_mac_pathname (true_pathname, mac_pathname, MAXPATHLEN+1) == 0)
424 return -1;
426 c2pstr (mac_pathname);
427 hfpb.ioNamePtr = mac_pathname;
428 hfpb.ioVRefNum = 0; /* ignored unless name is invalid */
429 hfpb.ioDirID = 0; /* parent is the root */
431 errno = PBDirCreate ((HParmBlkPtr) &hfpb, false);
432 /* just return the Mac OSErr code for now */
433 return errno == noErr ? 0 : -1;
437 #undef rmdir
438 sys_rmdir (const char *dirname)
440 HFileParam hfpb;
441 char mac_pathname[MAXPATHLEN+1];
443 if (unix_to_mac_pathname (dirname, mac_pathname, MAXPATHLEN+1) == 0)
444 return -1;
446 c2pstr (mac_pathname);
447 hfpb.ioNamePtr = mac_pathname;
448 hfpb.ioVRefNum = 0; /* ignored unless name is invalid */
449 hfpb.ioDirID = 0; /* parent is the root */
451 errno = PBHDelete ((HParmBlkPtr) &hfpb, false);
452 return errno == noErr ? 0 : -1;
456 #ifdef __MRC__
457 /* No implementation yet. */
459 execvp (const char *path, ...)
461 return -1;
463 #endif /* __MRC__ */
467 utime (const char *path, const struct utimbuf *times)
469 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
470 int len;
471 char mac_pathname[MAXPATHLEN+1];
472 CInfoPBRec cipb;
474 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
475 return -1;
477 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
478 if (len > -1)
479 fully_resolved_name[len] = '\0';
480 else
481 strcpy (fully_resolved_name, true_pathname);
483 if (!unix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
484 return -1;
486 c2pstr (mac_pathname);
487 cipb.hFileInfo.ioNamePtr = mac_pathname;
488 cipb.hFileInfo.ioVRefNum = 0;
489 cipb.hFileInfo.ioDirID = 0;
490 cipb.hFileInfo.ioFDirIndex = 0;
491 /* set to 0 to get information about specific dir or file */
493 errno = PBGetCatInfo (&cipb, false);
494 if (errno != noErr)
495 return -1;
497 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* bit 4 = 1 for directories */
499 if (times)
500 cipb.dirInfo.ioDrMdDat = times->modtime + MAC_UNIX_EPOCH_DIFF;
501 else
502 GetDateTime (&cipb.dirInfo.ioDrMdDat);
504 else
506 if (times)
507 cipb.hFileInfo.ioFlMdDat = times->modtime + MAC_UNIX_EPOCH_DIFF;
508 else
509 GetDateTime (&cipb.hFileInfo.ioFlMdDat);
512 errno = PBSetCatInfo (&cipb, false);
513 return errno == noErr ? 0 : -1;
517 #ifndef F_OK
518 #define F_OK 0
519 #endif
520 #ifndef X_OK
521 #define X_OK 1
522 #endif
523 #ifndef W_OK
524 #define W_OK 2
525 #endif
527 /* Like stat, but test for access mode in hfpb.ioFlAttrib */
529 access (const char *path, int mode)
531 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
532 int len;
533 char mac_pathname[MAXPATHLEN+1];
534 CInfoPBRec cipb;
536 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
537 return -1;
539 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
540 if (len > -1)
541 fully_resolved_name[len] = '\0';
542 else
543 strcpy (fully_resolved_name, true_pathname);
545 if (!unix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
546 return -1;
548 c2pstr (mac_pathname);
549 cipb.hFileInfo.ioNamePtr = mac_pathname;
550 cipb.hFileInfo.ioVRefNum = 0;
551 cipb.hFileInfo.ioDirID = 0;
552 cipb.hFileInfo.ioFDirIndex = 0;
553 /* set to 0 to get information about specific dir or file */
555 errno = PBGetCatInfo (&cipb, false);
556 if (errno != noErr)
557 return -1;
559 if (mode == F_OK) /* got this far, file exists */
560 return 0;
562 if (mode & X_OK)
563 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* path refers to a directory */
564 return 0;
565 else
567 if (cipb.hFileInfo.ioFlFndrInfo.fdType == 'APPL')
568 return 0;
569 else
570 return -1;
573 if (mode & W_OK)
574 return (cipb.hFileInfo.ioFlAttrib & 0x1) ? -1 : 0;
575 /* don't allow if lock bit is on */
577 return -1;
581 #define DEV_NULL_FD 0x10000
583 #undef open
585 sys_open (const char *path, int oflag)
587 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
588 int len;
589 char mac_pathname[MAXPATHLEN+1];
591 if (strcmp (path, "/dev/null") == 0)
592 return DEV_NULL_FD; /* some bogus fd to be ignored in write */
594 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
595 return -1;
597 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
598 if (len > -1)
599 fully_resolved_name[len] = '\0';
600 else
601 strcpy (fully_resolved_name, true_pathname);
603 if (!unix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
604 return -1;
605 else
607 #ifdef __MRC__
608 if (oflag == O_WRONLY || oflag == O_RDWR)
609 fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
610 #endif
611 return open (mac_pathname, oflag);
616 #undef creat
618 sys_creat (const char *path, mode_t mode)
620 char true_pathname[MAXPATHLEN+1];
621 int len;
622 char mac_pathname[MAXPATHLEN+1];
624 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
625 return -1;
627 if (!unix_to_mac_pathname (true_pathname, mac_pathname, MAXPATHLEN+1))
628 return -1;
629 else
631 #ifdef __MRC__
632 int result = creat (mac_pathname);
633 fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
634 return result;
635 #else
636 return creat (mac_pathname, mode);
637 #endif
642 #undef unlink
644 sys_unlink (const char *path)
646 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
647 int len;
648 char mac_pathname[MAXPATHLEN+1];
650 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
651 return -1;
653 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
654 if (len > -1)
655 fully_resolved_name[len] = '\0';
656 else
657 strcpy (fully_resolved_name, true_pathname);
659 if (!unix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
660 return -1;
661 else
662 return unlink (mac_pathname);
666 #undef read
668 sys_read (int fildes, char *buf, int count)
670 if (fildes == 0) /* this should not be used for console input */
671 return -1;
672 else
673 #ifdef CODEWARRIOR_VERSION_6
674 return _read (fildes, buf, count);
675 #else
676 return read (fildes, buf, count);
677 #endif
681 #undef write
683 sys_write (int fildes, const char *buf, int count)
685 if (fildes == DEV_NULL_FD)
686 return count;
687 else
688 #ifdef CODEWARRIOR_VERSION_6
689 return _write (fildes, buf, count);
690 #else
691 return write (fildes, buf, count);
692 #endif
696 #undef rename
698 sys_rename (const char * old_name, const char * new_name)
700 char true_old_pathname[MAXPATHLEN+1], true_new_pathname[MAXPATHLEN+1];
701 char fully_resolved_old_name[MAXPATHLEN+1];
702 int len;
703 char mac_old_name[MAXPATHLEN+1], mac_new_name[MAXPATHLEN+1];
705 if (find_true_pathname (old_name, true_old_pathname, MAXPATHLEN+1) == -1)
706 return -1;
708 len = readlink (true_old_pathname, fully_resolved_old_name, MAXPATHLEN);
709 if (len > -1)
710 fully_resolved_old_name[len] = '\0';
711 else
712 strcpy (fully_resolved_old_name, true_old_pathname);
714 if (find_true_pathname (new_name, true_new_pathname, MAXPATHLEN+1) == -1)
715 return -1;
717 if (strcmp (fully_resolved_old_name, true_new_pathname) == 0)
718 return 0;
720 if (!unix_to_mac_pathname (fully_resolved_old_name,
721 mac_old_name,
722 MAXPATHLEN+1))
723 return -1;
725 if (!unix_to_mac_pathname(true_new_pathname, mac_new_name, MAXPATHLEN+1))
726 return -1;
728 /* If a file with new_name already exists, rename deletes the old
729 file in Unix. CW version fails in these situation. So we add a
730 call to unlink here. */
731 (void) unlink (mac_new_name);
733 return rename (mac_old_name, mac_new_name);
737 #undef fopen
738 extern FILE *fopen (const char *name, const char *mode);
739 FILE *
740 sys_fopen (const char *name, const char *mode)
742 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
743 int len;
744 char mac_pathname[MAXPATHLEN+1];
746 if (find_true_pathname (name, true_pathname, MAXPATHLEN+1) == -1)
747 return 0;
749 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
750 if (len > -1)
751 fully_resolved_name[len] = '\0';
752 else
753 strcpy (fully_resolved_name, true_pathname);
755 if (!unix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
756 return 0;
757 else
759 #ifdef __MRC__
760 if (mode[0] == 'w' || mode[0] == 'a')
761 fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
762 #endif
763 return fopen (mac_pathname, mode);
768 #include <Events.h>
770 long target_ticks = 0;
772 #ifdef __MRC__
773 __sigfun alarm_signal_func = (__sigfun) 0;
774 #elif __MWERKS__
775 __signal_func_ptr alarm_signal_func = (__signal_func_ptr) 0;
776 #else
777 You lose!!!
778 #endif
781 /* These functions simulate SIG_ALRM. The stub for function signal
782 stores the signal handler function in alarm_signal_func if a
783 SIG_ALRM is encountered. check_alarm is called in XTread_socket,
784 which emacs calls periodically. A pending alarm is represented by
785 a non-zero target_ticks value. check_alarm calls the handler
786 function pointed to by alarm_signal_func if one has been set up and
787 an alarm is pending. */
789 void
790 check_alarm ()
792 if (target_ticks && TickCount () > target_ticks)
794 target_ticks = 0;
795 if (alarm_signal_func)
796 (*alarm_signal_func)(SIGALRM);
802 select(n, rfds, wfds, efds, timeout)
803 int n;
804 SELECT_TYPE *rfds;
805 SELECT_TYPE *wfds;
806 SELECT_TYPE *efds;
807 struct timeval *timeout;
809 EMACS_TIME end_time, now;
810 EventRecord e;
811 unsigned long final_tick;
813 /* Can only handle wait for keyboard input. */
814 if (n > 1 || wfds || efds)
815 return -1;
817 EMACS_GET_TIME (end_time);
818 EMACS_ADD_TIME (end_time, end_time, *timeout);
822 /* Also return true if an event other than a keyDown has
823 occurred. This causes kbd_buffer_get_event in keyboard.c to
824 call read_avail_input which in turn calls XTread_socket to
825 poll for these events. Otherwise these never get processed
826 except but a very slow poll timer. */
827 if (FD_ISSET (0, rfds) && EventAvail (everyEvent, &e))
828 return 1;
830 /* Also check movement of the mouse. */
832 Point mouse_pos;
833 static Point old_mouse_pos = {-1, -1};
835 GetMouse (&mouse_pos);
836 if (!EqualPt (mouse_pos, old_mouse_pos))
838 old_mouse_pos = mouse_pos;
839 return 1;
843 Delay (1UL, &final_tick);
845 EMACS_GET_TIME (now);
846 EMACS_SUB_TIME (now, end_time, now);
848 while (!EMACS_TIME_NEG_P (now));
850 return 0;
854 /* Called in sys_select to wait for an alarm signal to arrive. */
857 pause ()
859 unsigned long final_tick;
861 if (!target_ticks) /* no alarm pending */
862 return -1;
864 while (TickCount () <= target_ticks)
865 Delay (1UL, &final_tick); /* wait 1/60 second before retrying */
867 target_ticks = 0;
868 if (alarm_signal_func)
869 (*alarm_signal_func)(SIGALRM);
871 return 0;
876 alarm (int seconds)
878 long remaining = target_ticks ? (TickCount () - target_ticks) / 60 : 0;
880 target_ticks = seconds ? TickCount () + 60 * seconds : 0;
882 return (remaining < 0) ? 0 : (unsigned int) remaining;
886 #undef signal
887 #ifdef __MRC__
888 extern __sigfun signal (int signal, __sigfun signal_func);
889 __sigfun
890 sys_signal (int signal_num, __sigfun signal_func)
891 #elif __MWERKS__
892 extern __signal_func_ptr signal (int signal, __signal_func_ptr signal_func);
893 __signal_func_ptr
894 sys_signal (int signal_num, __signal_func_ptr signal_func)
895 #else
896 You lose!!!
897 #endif
899 if (signal_num != SIGALRM)
900 return signal (signal_num, signal_func);
901 else
903 #ifdef __MRC__
904 __sigfun old_signal_func;
905 #elif __MWERKS__
906 __signal_func_ptr old_signal_func;
907 #else
908 You lose!!!
909 #endif
910 old_signal_func = alarm_signal_func;
911 alarm_signal_func = signal_func;
912 return old_signal_func;
917 /* gettimeofday should return the amount of time (in a timeval
918 structure) since midnight today. The toolbox function Microseconds
919 returns the number of microseconds (in a UnsignedWide value) since
920 the machine was booted. Also making this complicated is WideAdd,
921 WideSubtract, etc. take wide values. */
924 gettimeofday (tp)
925 struct timeval *tp;
927 static inited = 0;
928 static wide wall_clock_at_epoch, clicks_at_epoch;
929 UnsignedWide uw_microseconds;
930 wide w_microseconds;
931 time_t sys_time (time_t *);
933 /* If this function is called for the first time, record the number
934 of seconds since midnight and the number of microseconds since
935 boot at the time of this first call. */
936 if (!inited)
938 time_t systime;
939 inited = 1;
940 systime = sys_time (NULL);
941 /* Store microseconds since midnight in wall_clock_at_epoch. */
942 WideMultiply (systime, 1000000L, &wall_clock_at_epoch);
943 Microseconds (&uw_microseconds);
944 /* Store microseconds since boot in clicks_at_epoch. */
945 clicks_at_epoch.hi = uw_microseconds.hi;
946 clicks_at_epoch.lo = uw_microseconds.lo;
949 /* Get time since boot */
950 Microseconds (&uw_microseconds);
952 /* Convert to time since midnight*/
953 w_microseconds.hi = uw_microseconds.hi;
954 w_microseconds.lo = uw_microseconds.lo;
955 WideSubtract (&w_microseconds, &clicks_at_epoch);
956 WideAdd (&w_microseconds, &wall_clock_at_epoch);
957 tp->tv_sec = WideDivide (&w_microseconds, 1000000L, &tp->tv_usec);
959 return 0;
963 #ifdef __MRC__
964 unsigned int
965 sleep (unsigned int seconds)
967 unsigned long final_tick;
969 Delay (seconds * 60UL, &final_tick);
970 return (0);
972 #endif /* __MRC__ */
975 /* The time functions adjust time values according to the difference
976 between the Unix and CW epoches. */
978 #undef gmtime
979 extern struct tm *gmtime (const time_t *);
980 struct tm *
981 sys_gmtime (const time_t *timer)
983 time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
985 return gmtime (&unix_time);
989 #undef localtime
990 extern struct tm *localtime (const time_t *);
991 struct tm *
992 sys_localtime (const time_t *timer)
994 #ifdef CODEWARRIOR_VERSION_6
995 time_t unix_time = *timer;
996 #else
997 time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
998 #endif
1000 return localtime (&unix_time);
1004 #undef ctime
1005 extern char *ctime (const time_t *);
1006 char *
1007 sys_ctime (const time_t *timer)
1009 #ifdef CODEWARRIOR_VERSION_6
1010 time_t unix_time = *timer;
1011 #else
1012 time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
1013 #endif
1015 return ctime (&unix_time);
1019 #undef time
1020 extern time_t time (time_t *);
1021 time_t
1022 sys_time (time_t *timer)
1024 #ifdef CODEWARRIOR_VERSION_6
1025 time_t mac_time = time (NULL);
1026 #else
1027 time_t mac_time = time (NULL) - CW_OR_MPW_UNIX_EPOCH_DIFF;
1028 #endif
1030 if (timer)
1031 *timer = mac_time;
1033 return mac_time;
1037 /* MPW strftime broken for "%p" format */
1038 #ifdef __MRC__
1039 #undef strftime
1040 #include <time.h>
1041 size_t
1042 sys_strftime (char * s, size_t maxsize, const char * format,
1043 const struct tm * timeptr)
1045 if (strcmp (format, "%p") == 0)
1047 if (maxsize < 3)
1048 return 0;
1049 if (timeptr->tm_hour < 12)
1051 strcpy (s, "AM");
1052 return 2;
1054 else
1056 strcpy (s, "PM");
1057 return 2;
1060 else
1061 return strftime (s, maxsize, format, timeptr);
1063 #endif /* __MRC__ */
1066 /* no subprocesses, empty wait */
1069 wait (int pid)
1071 return 0;
1075 void
1076 croak (char *badfunc)
1078 printf ("%s not yet implemented\r\n", badfunc);
1079 exit (1);
1083 char *
1084 index (const char * str, int chr)
1086 return strchr (str, chr);
1090 char *
1091 mktemp (char *template)
1093 int len, k;
1094 static seqnum = 0;
1096 len = strlen (template);
1097 k = len - 1;
1098 while (k >= 0 && template[k] == 'X')
1099 k--;
1101 k++; /* make k index of first 'X' */
1103 if (k < len)
1105 /* Zero filled, number of digits equal to the number of X's. */
1106 sprintf (&template[k], "%0*d", len-k, seqnum++);
1108 return template;
1110 else
1111 return 0;
1115 /* Emulate getpwuid, getpwnam and others. */
1117 #define PASSWD_FIELD_SIZE 256
1119 static char my_passwd_name[PASSWD_FIELD_SIZE];
1120 static char my_passwd_dir[MAXPATHLEN+1];
1122 static struct passwd my_passwd =
1124 my_passwd_name,
1125 my_passwd_dir,
1129 /* Initialized by main () in macterm.c to pathname of emacs directory. */
1131 char emacs_passwd_dir[MAXPATHLEN+1];
1133 char *
1134 getwd (char *);
1136 void
1137 init_emacs_passwd_dir ()
1139 int found = false;
1141 if (getwd (emacs_passwd_dir) && getwd (my_passwd_dir))
1143 /* Need pathname of first ancestor that begins with "emacs"
1144 since Mac emacs application is somewhere in the emacs-*
1145 tree. */
1146 int len = strlen (emacs_passwd_dir);
1147 int j = len - 1;
1148 /* j points to the "/" following the directory name being
1149 compared. */
1150 int i = j - 1;
1151 while (i >= 0 && !found)
1153 while (i >= 0 && emacs_passwd_dir[i] != '/')
1154 i--;
1155 if (emacs_passwd_dir[i] == '/' && i+5 < len)
1156 found = (strncmp (&(emacs_passwd_dir[i+1]), "emacs", 5) == 0);
1157 if (found)
1158 emacs_passwd_dir[j+1] = '\0';
1159 else
1161 j = i;
1162 i = j - 1;
1167 if (!found)
1169 /* Setting to "/" probably won't work but set it to something
1170 anyway. */
1171 strcpy (emacs_passwd_dir, "/");
1172 strcpy (my_passwd_dir, "/");
1177 static struct passwd emacs_passwd =
1179 "emacs",
1180 emacs_passwd_dir,
1183 static int my_passwd_inited = 0;
1186 static void
1187 init_my_passwd ()
1189 char **owner_name;
1191 /* Note: my_passwd_dir initialized in int_emacs_passwd_dir to
1192 directory where Emacs was started. */
1194 owner_name = (char **) GetResource ('STR ',-16096);
1195 if (owner_name)
1197 HLock (owner_name);
1198 BlockMove ((unsigned char *) *owner_name,
1199 (unsigned char *) my_passwd_name,
1200 *owner_name[0]+1);
1201 HUnlock (owner_name);
1202 p2cstr ((unsigned char *) my_passwd_name);
1204 else
1205 my_passwd_name[0] = 0;
1209 struct passwd *
1210 getpwuid (uid_t uid)
1212 if (!my_passwd_inited)
1214 init_my_passwd ();
1215 my_passwd_inited = 1;
1218 return &my_passwd;
1222 struct passwd *
1223 getpwnam (const char *name)
1225 if (strcmp (name, "emacs") == 0)
1226 return &emacs_passwd;
1228 if (!my_passwd_inited)
1230 init_my_passwd ();
1231 my_passwd_inited = 1;
1234 return &my_passwd;
1238 /* The functions fork, kill, sigsetmask, sigblock, request_sigio,
1239 setpgrp, setpriority, and unrequest_sigio are defined to be empty
1240 as in msdos.c. */
1244 fork ()
1246 return -1;
1251 kill (int x, int y)
1253 return -1;
1257 void
1258 sys_subshell ()
1260 error ("Can't spawn subshell");
1265 sigsetmask (int x)
1267 return 0;
1272 sigblock (int mask)
1274 return 0;
1278 void
1279 request_sigio (void)
1284 void
1285 unrequest_sigio (void)
1291 setpgrp ()
1293 return 0;
1297 /* No pipes yet. */
1300 pipe (int _fildes[2])
1302 errno = EACCES;
1303 return -1;
1307 /* Hard and symbolic links. */
1310 symlink (const char *name1, const char *name2)
1312 errno = ENOENT;
1313 return -1;
1318 link (const char *name1, const char *name2)
1320 errno = ENOENT;
1321 return -1;
1325 /* Determine the path name of the file specified by VREFNUM, DIRID,
1326 and NAME and place that in the buffer PATH of length
1327 MAXPATHLEN. */
1329 path_from_vol_dir_name (char *path, int man_path_len, short vol_ref_num,
1330 long dir_id, ConstStr255Param name)
1332 Str255 dir_name;
1333 CInfoPBRec cipb;
1334 OSErr err;
1336 if (strlen (name) > man_path_len)
1337 return 0;
1339 memcpy (dir_name, name, name[0]+1);
1340 memcpy (path, name, name[0]+1);
1341 p2cstr (path);
1343 cipb.dirInfo.ioDrParID = dir_id;
1344 cipb.dirInfo.ioNamePtr = dir_name;
1348 cipb.dirInfo.ioVRefNum = vol_ref_num;
1349 cipb.dirInfo.ioFDirIndex = -1;
1350 cipb.dirInfo.ioDrDirID = cipb.dirInfo.ioDrParID;
1351 /* go up to parent each time */
1353 err = PBGetCatInfo (&cipb, false);
1354 if (err != noErr)
1355 return 0;
1357 p2cstr (dir_name);
1358 if (strlen (dir_name) + strlen (path) + 1 >= man_path_len)
1359 return 0;
1361 strcat (dir_name, ":");
1362 strcat (dir_name, path);
1363 /* attach to front since we're going up directory tree */
1364 strcpy (path, dir_name);
1366 while (cipb.dirInfo.ioDrDirID != fsRtDirID);
1367 /* stop when we see the volume's root directory */
1369 return 1; /* success */
1374 readlink (const char *path, char *buf, int bufsiz)
1376 char mac_sym_link_name[MAXPATHLEN+1];
1377 OSErr err;
1378 FSSpec fsspec;
1379 Boolean target_is_folder, was_aliased;
1380 Str255 directory_name, mac_pathname;
1381 CInfoPBRec cipb;
1383 if (unix_to_mac_pathname (path, mac_sym_link_name, MAXPATHLEN+1) == 0)
1384 return -1;
1386 c2pstr (mac_sym_link_name);
1387 err = FSMakeFSSpec (0, 0, mac_sym_link_name, &fsspec);
1388 if (err != noErr)
1390 errno = ENOENT;
1391 return -1;
1394 err = ResolveAliasFile (&fsspec, true, &target_is_folder, &was_aliased);
1395 if (err != noErr || !was_aliased)
1397 errno = ENOENT;
1398 return -1;
1401 if (path_from_vol_dir_name (mac_pathname, 255, fsspec.vRefNum, fsspec.parID,
1402 fsspec.name) == 0)
1404 errno = ENOENT;
1405 return -1;
1408 if (mac_to_unix_pathname (mac_pathname, buf, bufsiz) == 0)
1410 errno = ENOENT;
1411 return -1;
1414 return strlen (buf);
1418 /* Convert a path to one with aliases fully expanded. */
1420 static int
1421 find_true_pathname (const char *path, char *buf, int bufsiz)
1423 char *q, temp[MAXPATHLEN+1];
1424 const char *p;
1425 int len;
1427 if (bufsiz <= 0 || path == 0 || path[0] == '\0')
1428 return -1;
1430 buf[0] = '\0';
1432 p = path;
1433 if (*p == '/')
1434 q = strchr (p + 1, '/');
1435 else
1436 q = strchr (p, '/');
1437 len = 0; /* loop may not be entered, e.g., for "/" */
1439 while (q)
1441 strcpy (temp, buf);
1442 strncat (temp, p, q - p);
1443 len = readlink (temp, buf, bufsiz);
1444 if (len <= -1)
1446 if (strlen (temp) + 1 > bufsiz)
1447 return -1;
1448 strcpy (buf, temp);
1450 strcat (buf, "/");
1451 len++;
1452 p = q + 1;
1453 q = strchr(p, '/');
1456 if (len + strlen (p) + 1 >= bufsiz)
1457 return -1;
1459 strcat (buf, p);
1460 return len + strlen (p);
1464 mode_t
1465 umask (mode_t numask)
1467 static mode_t mask = 022;
1468 mode_t oldmask = mask;
1469 mask = numask;
1470 return oldmask;
1475 chmod (const char *path, mode_t mode)
1477 /* say it always succeed for now */
1478 return 0;
1483 dup (int oldd)
1485 #ifdef __MRC__
1486 return fcntl (oldd, F_DUPFD, 0);
1487 #elif __MWERKS__
1488 /* current implementation of fcntl in fcntl.mac.c simply returns old
1489 descriptor */
1490 return fcntl (oldd, F_DUPFD);
1491 #else
1492 You lose!!!
1493 #endif
1497 /* This is from the original sysdep.c. Emulate BSD dup2. First close
1498 newd if it already exists. Then, attempt to dup oldd. If not
1499 successful, call dup2 recursively until we are, then close the
1500 unsuccessful ones. */
1503 dup2 (int oldd, int newd)
1505 int fd, ret;
1507 close (newd);
1509 fd = dup (oldd);
1510 if (fd == -1)
1511 return -1;
1512 if (fd == newd)
1513 return newd;
1514 ret = dup2 (oldd, newd);
1515 close (fd);
1516 return ret;
1520 /* let it fail for now */
1522 char *
1523 sbrk (int incr)
1525 return (char *) -1;
1530 fsync (int fd)
1532 return 0;
1537 ioctl (int d, int request, void *argp)
1539 return -1;
1543 #ifdef __MRC__
1545 isatty (int fildes)
1547 if (fildes >=0 && fildes <= 2)
1548 return 1;
1549 else
1550 return 0;
1555 getgid ()
1557 return 100;
1562 getegid ()
1564 return 100;
1569 getuid ()
1571 return 200;
1576 geteuid ()
1578 return 200;
1580 #endif /* __MRC__ */
1583 #ifdef __MWERKS__
1584 #ifndef CODEWARRIOR_VERSION_6
1585 #undef getpid
1587 getpid ()
1589 return 9999;
1591 #endif
1592 #endif /* __MWERKS__ */
1595 /* Return the path to the directory in which Emacs can create
1596 temporary files. The MacOS "temporary items" directory cannot be
1597 used because it removes the file written by a process when it
1598 exits. In that sense it's more like "/dev/null" than "/tmp" (but
1599 again not exactly). And of course Emacs needs to read back the
1600 files written by its subprocesses. So here we write the files to a
1601 directory "Emacs" in the Preferences Folder. This directory is
1602 created if it does not exist. */
1604 static char *
1605 get_temp_dir_name ()
1607 static char *temp_dir_name = NULL;
1608 short vol_ref_num;
1609 long dir_id;
1610 OSErr err;
1611 Str255 dir_name, full_path;
1612 CInfoPBRec cpb;
1613 char unix_dir_name[MAXPATHLEN+1];
1614 DIR *dir;
1616 /* Cache directory name with pointer temp_dir_name.
1617 Look for it only the first time. */
1618 if (!temp_dir_name)
1620 err = FindFolder (kOnSystemDisk, kPreferencesFolderType, kCreateFolder,
1621 &vol_ref_num, &dir_id);
1622 if (err != noErr)
1623 return NULL;
1625 if (!path_from_vol_dir_name (full_path, 255, vol_ref_num, dir_id, "\p"))
1626 return NULL;
1628 if (strlen (full_path) + 6 <= MAXPATHLEN)
1629 strcat (full_path, "Emacs:");
1630 else
1631 return NULL;
1633 if (!mac_to_unix_pathname (full_path, unix_dir_name, MAXPATHLEN+1))
1634 return NULL;
1636 dir = opendir (unix_dir_name); /* check whether temp directory exists */
1637 if (dir)
1638 closedir (dir);
1639 else if (mkdir (unix_dir_name, 0700) != 0) /* create it if not */
1640 return NULL;
1642 temp_dir_name = (char *) malloc (strlen (unix_dir_name) + 1);
1643 strcpy (temp_dir_name, unix_dir_name);
1646 return temp_dir_name;
1650 /* Allocate and construct an array of pointers to strings from a list
1651 of strings stored in a 'STR#' resource. The returned pointer array
1652 is stored in the style of argv and environ: if the 'STR#' resource
1653 contains numString strings, an pointer array with numString+1
1654 elements is returned in which the last entry contains a null
1655 pointer. The pointer to the pointer array is passed by pointer in
1656 parameter t. The resource ID of the 'STR#' resource is passed in
1657 parameter StringListID.
1660 void
1661 get_string_list (char ***t, short string_list_id)
1663 Handle h;
1664 Ptr p;
1665 int i, num_strings;
1667 h = GetResource ('STR#', string_list_id);
1668 if (h)
1670 HLock (h);
1671 p = *h;
1672 num_strings = * (short *) p;
1673 p += sizeof(short);
1674 *t = (char **) malloc (sizeof (char *) * (num_strings + 1));
1675 for (i = 0; i < num_strings; i++)
1677 short length = *p++;
1678 (*t)[i] = (char *) malloc (length + 1);
1679 strncpy ((*t)[i], p, length);
1680 (*t)[i][length] = '\0';
1681 p += length;
1683 (*t)[num_strings] = 0;
1684 HUnlock (h);
1686 else
1688 /* Return no string in case GetResource fails. Bug fixed by
1689 Ikegami Tsutomu. Caused MPW build to crash without sym -on
1690 option (no sym -on implies -opt local). */
1691 *t = (char **) malloc (sizeof (char *));
1692 (*t)[0] = 0;
1697 static char *
1698 get_path_to_system_folder ()
1700 short vol_ref_num;
1701 long dir_id;
1702 OSErr err;
1703 Str255 dir_name, full_path;
1704 CInfoPBRec cpb;
1705 static char system_folder_unix_name[MAXPATHLEN+1];
1706 DIR *dir;
1708 err = FindFolder (kOnSystemDisk, kSystemFolderType, kDontCreateFolder,
1709 &vol_ref_num, &dir_id);
1710 if (err != noErr)
1711 return NULL;
1713 if (!path_from_vol_dir_name (full_path, 255, vol_ref_num, dir_id, "\p"))
1714 return NULL;
1716 if (!mac_to_unix_pathname (full_path, system_folder_unix_name, MAXPATHLEN+1))
1717 return NULL;
1719 return system_folder_unix_name;
1723 char **environ;
1725 #define ENVIRON_STRING_LIST_ID 128
1727 /* Get environment variable definitions from STR# resource. */
1729 void
1730 init_environ ()
1732 int i;
1734 get_string_list (&environ, ENVIRON_STRING_LIST_ID);
1736 i = 0;
1737 while (environ[i])
1738 i++;
1740 /* Make HOME directory the one Emacs starts up in if not specified
1741 by resource. */
1742 if (getenv ("HOME") == NULL)
1744 environ = (char **) realloc (environ, sizeof (char *) * (i + 2));
1745 if (environ)
1747 environ[i] = (char *) malloc (strlen (my_passwd_dir) + 6);
1748 if (environ[i])
1750 strcpy (environ[i], "HOME=");
1751 strcat (environ[i], my_passwd_dir);
1753 environ[i+1] = 0;
1754 i++;
1758 /* Make HOME directory the one Emacs starts up in if not specified
1759 by resource. */
1760 if (getenv ("MAIL") == NULL)
1762 environ = (char **) realloc (environ, sizeof (char *) * (i + 2));
1763 if (environ)
1765 char * path_to_system_folder = get_path_to_system_folder ();
1766 environ[i] = (char *) malloc (strlen (path_to_system_folder) + 22);
1767 if (environ[i])
1769 strcpy (environ[i], "MAIL=");
1770 strcat (environ[i], path_to_system_folder);
1771 strcat (environ[i], "Eudora Folder/In");
1773 environ[i+1] = 0;
1779 /* Return the value of the environment variable NAME. */
1781 char *
1782 getenv (const char *name)
1784 int length = strlen(name);
1785 char **e;
1787 for (e = environ; *e != 0; e++)
1788 if (strncmp(*e, name, length) == 0 && (*e)[length] == '=')
1789 return &(*e)[length + 1];
1791 if (strcmp (name, "TMPDIR") == 0)
1792 return get_temp_dir_name ();
1794 return 0;
1798 #ifdef __MRC__
1799 /* see Interfaces&Libraries:Interfaces:CIncludes:signal.h */
1800 char *sys_siglist[] =
1802 "Zero is not a signal!!!",
1803 "Abort", /* 1 */
1804 "Interactive user interrupt", /* 2 */ "?",
1805 "Floating point exception", /* 4 */ "?", "?", "?",
1806 "Illegal instruction", /* 8 */ "?", "?", "?", "?", "?", "?", "?",
1807 "Segment violation", /* 16 */ "?", "?", "?", "?", "?", "?", "?",
1808 "?", "?", "?", "?", "?", "?", "?", "?",
1809 "Terminal" /* 32 */
1811 #elif __MWERKS__
1812 char *sys_siglist[] =
1814 "Zero is not a signal!!!",
1815 "Abort",
1816 "Floating point exception",
1817 "Illegal instruction",
1818 "Interactive user interrupt",
1819 "Segment violation",
1820 "Terminal"
1822 #else
1823 You lose!!!
1824 #endif
1827 #include <utsname.h>
1830 uname (struct utsname *name)
1832 char **system_name;
1833 system_name = GetString (-16413); /* IM - Resource Manager Reference */
1834 if (system_name)
1836 BlockMove (*system_name, name->nodename, (*system_name)[0]+1);
1837 p2cstr (name->nodename);
1838 return 0;
1840 else
1841 return -1;
1845 #include <Processes.h>
1846 #include <EPPC.h>
1848 /* Event class of HLE sent to subprocess. */
1849 const OSType kEmacsSubprocessSend = 'ESND';
1851 /* Event class of HLE sent back from subprocess. */
1852 const OSType kEmacsSubprocessReply = 'ERPY';
1855 char *
1856 mystrchr (char *s, char c)
1858 while (*s && *s != c)
1860 if (*s == '\\')
1861 s++;
1862 s++;
1865 if (*s)
1867 *s = '\0';
1868 return s;
1870 else
1871 return NULL;
1875 char *
1876 mystrtok (char *s)
1878 while (*s)
1879 s++;
1881 return s + 1;
1885 void
1886 mystrcpy (char *to, char *from)
1888 while (*from)
1890 if (*from == '\\')
1891 from++;
1892 *to++ = *from++;
1894 *to = '\0';
1898 /* Start a Mac subprocess. Arguments for it is passed in argv (null
1899 terminated). The process should run with the default directory
1900 "workdir", read input from "infn", and write output and error to
1901 "outfn" and "errfn", resp. The Process Manager call
1902 LaunchApplication is used to start the subprocess. We use high
1903 level events as the mechanism to pass arguments to the subprocess
1904 and to make Emacs wait for the subprocess to terminate and pass
1905 back a result code. The bulk of the code here packs the arguments
1906 into one message to be passed together with the high level event.
1907 Emacs also sometimes starts a subprocess using a shell to perform
1908 wildcard filename expansion. Since we don't really have a shell on
1909 the Mac, this case is detected and the starting of the shell is
1910 by-passed. We really need to add code here to do filename
1911 expansion to support such functionality. */
1914 run_mac_command (argv, workdir, infn, outfn, errfn)
1915 unsigned char **argv;
1916 const char *workdir;
1917 const char *infn, *outfn, *errfn;
1919 char macappname[MAXPATHLEN+1], macworkdir[MAXPATHLEN+1];
1920 char macinfn[MAXPATHLEN+1], macoutfn[MAXPATHLEN+1], macerrfn[MAXPATHLEN+1];
1921 int paramlen, argc, newargc, j, retries;
1922 char **newargv, *param, *p;
1923 OSErr iErr;
1924 FSSpec spec;
1925 LaunchParamBlockRec lpbr;
1926 EventRecord send_event, reply_event;
1927 RgnHandle cursor_region_handle;
1928 TargetID targ;
1929 unsigned long ref_con, len;
1931 if (unix_to_mac_pathname (workdir, macworkdir, MAXPATHLEN+1) == 0)
1932 return -1;
1933 if (unix_to_mac_pathname (infn, macinfn, MAXPATHLEN+1) == 0)
1934 return -1;
1935 if (unix_to_mac_pathname (outfn, macoutfn, MAXPATHLEN+1) == 0)
1936 return -1;
1937 if (unix_to_mac_pathname (errfn, macerrfn, MAXPATHLEN+1) == 0)
1938 return -1;
1940 paramlen = strlen (macworkdir) + strlen (macinfn) + strlen (macoutfn)
1941 + strlen (macerrfn) + 4; /* count nulls at end of strings */
1943 argc = 0;
1944 while (argv[argc])
1945 argc++;
1947 if (argc == 0)
1948 return -1;
1950 /* If a subprocess is invoked with a shell, we receive 3 arguments
1951 of the form: "<path to emacs bins>/sh" "-c" "<path to emacs
1952 bins>/<command> <command args>" */
1953 j = strlen (argv[0]);
1954 if (j >= 3 && strcmp (argv[0]+j-3, "/sh") == 0
1955 && argc == 3 && strcmp (argv[1], "-c") == 0)
1957 char *command, *t, tempmacpathname[MAXPATHLEN+1];
1959 /* The arguments for the command in argv[2] are separated by
1960 spaces. Count them and put the count in newargc. */
1961 command = (char *) alloca (strlen (argv[2])+2);
1962 strcpy (command, argv[2]);
1963 if (command[strlen (command) - 1] != ' ')
1964 strcat (command, " ");
1966 t = command;
1967 newargc = 0;
1968 t = mystrchr (t, ' ');
1969 while (t)
1971 newargc++;
1972 t = mystrchr (t+1, ' ');
1975 newargv = (char **) alloca (sizeof (char *) * newargc);
1977 t = command;
1978 for (j = 0; j < newargc; j++)
1980 newargv[j] = (char *) alloca (strlen (t) + 1);
1981 mystrcpy (newargv[j], t);
1983 t = mystrtok (t);
1984 paramlen += strlen (newargv[j]) + 1;
1987 if (strncmp (newargv[0], "~emacs/", 7) == 0)
1989 if (unix_to_mac_pathname (newargv[0], tempmacpathname, MAXPATHLEN+1)
1990 == 0)
1991 return -1;
1993 else
1994 { /* sometimes Emacs call "sh" without a path for the command */
1995 #if 0
1996 char *t = (char *) alloca (strlen (newargv[0]) + 7 + 1);
1997 strcpy (t, "~emacs/");
1998 strcat (t, newargv[0]);
1999 #endif
2000 Lisp_Object path;
2001 openp (Vexec_path, build_string (newargv[0]), EXEC_SUFFIXES, &path,
2004 if (NILP (path))
2005 return -1;
2006 if (unix_to_mac_pathname (XSTRING (path)->data, tempmacpathname,
2007 MAXPATHLEN+1) == 0)
2008 return -1;
2010 strcpy (macappname, tempmacpathname);
2012 else
2014 if (unix_to_mac_pathname (argv[0], macappname, MAXPATHLEN+1) == 0)
2015 return -1;
2017 newargv = (char **) alloca (sizeof (char *) * argc);
2018 newargc = argc;
2019 for (j = 1; j < argc; j++)
2021 if (strncmp (argv[j], "~emacs/", 7) == 0)
2023 char *t = strchr (argv[j], ' ');
2024 if (t)
2026 char tempcmdname[MAXPATHLEN+1], tempmaccmdname[MAXPATHLEN+1];
2027 strncpy (tempcmdname, argv[j], t-argv[j]);
2028 tempcmdname[t-argv[j]] = '\0';
2029 if (unix_to_mac_pathname (tempcmdname, tempmaccmdname,
2030 MAXPATHLEN+1) == 0)
2031 return -1;
2032 newargv[j] = (char *) alloca (strlen (tempmaccmdname)
2033 + strlen (t) + 1);
2034 strcpy (newargv[j], tempmaccmdname);
2035 strcat (newargv[j], t);
2037 else
2039 char tempmaccmdname[MAXPATHLEN+1];
2040 if (unix_to_mac_pathname (argv[j], tempmaccmdname,
2041 MAXPATHLEN+1) == 0)
2042 return -1;
2043 newargv[j] = (char *) alloca (strlen (tempmaccmdname)+1);
2044 strcpy (newargv[j], tempmaccmdname);
2047 else
2048 newargv[j] = argv[j];
2049 paramlen += strlen (newargv[j]) + 1;
2053 /* After expanding all the arguments, we now know the length of the
2054 parameter block to be sent to the subprocess as a message
2055 attached to the HLE. */
2056 param = (char *) malloc (paramlen + 1);
2057 if (!param)
2058 return -1;
2060 p = param;
2061 *p++ = newargc;
2062 /* first byte of message contains number of arguments for command */
2063 strcpy (p, macworkdir);
2064 p += strlen (macworkdir);
2065 *p++ = '\0';
2066 /* null terminate strings sent so it's possible to use strcpy over there */
2067 strcpy (p, macinfn);
2068 p += strlen (macinfn);
2069 *p++ = '\0';
2070 strcpy (p, macoutfn);
2071 p += strlen (macoutfn);
2072 *p++ = '\0';
2073 strcpy (p, macerrfn);
2074 p += strlen (macerrfn);
2075 *p++ = '\0';
2076 for (j = 1; j < newargc; j++)
2078 strcpy (p, newargv[j]);
2079 p += strlen (newargv[j]);
2080 *p++ = '\0';
2083 c2pstr (macappname);
2085 iErr = FSMakeFSSpec (0, 0, macappname, &spec);
2087 if (iErr != noErr)
2089 free (param);
2090 return -1;
2093 lpbr.launchBlockID = extendedBlock;
2094 lpbr.launchEPBLength = extendedBlockLen;
2095 lpbr.launchControlFlags = launchContinue + launchNoFileFlags;
2096 lpbr.launchAppSpec = &spec;
2097 lpbr.launchAppParameters = NULL;
2099 iErr = LaunchApplication (&lpbr); /* call the subprocess */
2100 if (iErr != noErr)
2102 free (param);
2103 return -1;
2106 send_event.what = kHighLevelEvent;
2107 send_event.message = kEmacsSubprocessSend;
2108 /* Event ID stored in "where" unused */
2110 retries = 3;
2111 /* OS may think current subprocess has terminated if previous one
2112 terminated recently. */
2115 iErr = PostHighLevelEvent (&send_event, &lpbr.launchProcessSN, 0, param,
2116 paramlen + 1, receiverIDisPSN);
2118 while (iErr == sessClosedErr && retries-- > 0);
2120 if (iErr != noErr)
2122 free (param);
2123 return -1;
2126 cursor_region_handle = NewRgn ();
2128 /* Wait for the subprocess to finish, when it will send us a ERPY
2129 high level event. */
2130 while (1)
2131 if (WaitNextEvent (highLevelEventMask, &reply_event, 180,
2132 cursor_region_handle)
2133 && reply_event.message == kEmacsSubprocessReply)
2134 break;
2136 /* The return code is sent through the refCon */
2137 iErr = AcceptHighLevelEvent (&targ, &ref_con, NULL, &len);
2138 if (iErr != noErr)
2140 DisposeHandle ((Handle) cursor_region_handle);
2141 free (param);
2142 return -1;
2145 DisposeHandle ((Handle) cursor_region_handle);
2146 free (param);
2148 return ref_con;
2152 DIR *
2153 opendir (const char *dirname)
2155 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
2156 char mac_pathname[MAXPATHLEN+1], vol_name[MAXPATHLEN+1];
2157 DIR *dirp;
2158 CInfoPBRec cipb;
2159 HVolumeParam vpb;
2160 int len, vol_name_len;
2162 if (find_true_pathname (dirname, true_pathname, MAXPATHLEN+1) == -1)
2163 return 0;
2165 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
2166 if (len > -1)
2167 fully_resolved_name[len] = '\0';
2168 else
2169 strcpy (fully_resolved_name, true_pathname);
2171 dirp = (DIR *) malloc (sizeof(DIR));
2172 if (!dirp)
2173 return 0;
2175 /* Handle special case when dirname is "/": sets up for readir to
2176 get all mount volumes. */
2177 if (strcmp (fully_resolved_name, "/") == 0)
2179 dirp->getting_volumes = 1; /* special all mounted volumes DIR struct */
2180 dirp->current_index = 1; /* index for first volume */
2181 return dirp;
2184 /* Handle typical cases: not accessing all mounted volumes. */
2185 if (!unix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
2186 return 0;
2188 /* Emacs calls opendir without the trailing '/', Mac needs trailing ':' */
2189 len = strlen (mac_pathname);
2190 if (mac_pathname[len - 1] != ':' && len < MAXPATHLEN)
2191 strcat (mac_pathname, ":");
2193 /* Extract volume name */
2194 vol_name_len = strchr (mac_pathname, ':') - mac_pathname;
2195 strncpy (vol_name, mac_pathname, vol_name_len);
2196 vol_name[vol_name_len] = '\0';
2197 strcat (vol_name, ":");
2199 c2pstr (mac_pathname);
2200 cipb.hFileInfo.ioNamePtr = mac_pathname;
2201 /* using full pathname so vRefNum and DirID ignored */
2202 cipb.hFileInfo.ioVRefNum = 0;
2203 cipb.hFileInfo.ioDirID = 0;
2204 cipb.hFileInfo.ioFDirIndex = 0;
2205 /* set to 0 to get information about specific dir or file */
2207 errno = PBGetCatInfo (&cipb, false);
2208 if (errno != noErr)
2210 errno = ENOENT;
2211 return 0;
2214 if (!(cipb.hFileInfo.ioFlAttrib & 0x10)) /* bit 4 = 1 for directories */
2215 return 0; /* not a directory */
2217 dirp->dir_id = cipb.dirInfo.ioDrDirID; /* used later in readdir */
2218 dirp->getting_volumes = 0;
2219 dirp->current_index = 1; /* index for first file/directory */
2221 c2pstr (vol_name);
2222 vpb.ioNamePtr = vol_name;
2223 /* using full pathname so vRefNum and DirID ignored */
2224 vpb.ioVRefNum = 0;
2225 vpb.ioVolIndex = -1;
2226 errno = PBHGetVInfo ((union HParamBlockRec *) &vpb, false);
2227 if (errno != noErr)
2229 errno = ENOENT;
2230 return 0;
2233 dirp->vol_ref_num = vpb.ioVRefNum;
2235 return dirp;
2239 closedir (DIR *dp)
2241 free (dp);
2243 return 0;
2247 struct dirent *
2248 readdir (DIR *dp)
2250 HParamBlockRec hpblock;
2251 CInfoPBRec cipb;
2252 static struct dirent s_dirent;
2253 static Str255 s_name;
2254 int done;
2255 char *p;
2257 /* Handle the root directory containing the mounted volumes. Call
2258 PBHGetVInfo specifying an index to obtain the info for a volume.
2259 PBHGetVInfo returns an error when it receives an index beyond the
2260 last volume, at which time we should return a nil dirent struct
2261 pointer. */
2262 if (dp->getting_volumes)
2264 hpblock.volumeParam.ioNamePtr = s_name;
2265 hpblock.volumeParam.ioVRefNum = 0;
2266 hpblock.volumeParam.ioVolIndex = dp->current_index;
2268 errno = PBHGetVInfo (&hpblock, false);
2269 if (errno != noErr)
2271 errno = ENOENT;
2272 return 0;
2275 p2cstr (s_name);
2276 strcat (s_name, "/"); /* need "/" for stat to work correctly */
2278 dp->current_index++;
2280 s_dirent.d_ino = hpblock.volumeParam.ioVRefNum;
2281 s_dirent.d_name = s_name;
2283 return &s_dirent;
2285 else
2287 cipb.hFileInfo.ioVRefNum = dp->vol_ref_num;
2288 cipb.hFileInfo.ioNamePtr = s_name;
2289 /* location to receive filename returned */
2291 /* return only visible files */
2292 done = false;
2293 while (!done)
2295 cipb.hFileInfo.ioDirID = dp->dir_id;
2296 /* directory ID found by opendir */
2297 cipb.hFileInfo.ioFDirIndex = dp->current_index;
2299 errno = PBGetCatInfo (&cipb, false);
2300 if (errno != noErr)
2302 errno = ENOENT;
2303 return 0;
2306 /* insist on an visibile entry */
2307 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* directory? */
2308 done = !(cipb.dirInfo.ioDrUsrWds.frFlags & fInvisible);
2309 else
2310 done = !(cipb.hFileInfo.ioFlFndrInfo.fdFlags & fInvisible);
2312 dp->current_index++;
2315 p2cstr (s_name);
2317 p = s_name;
2318 while (*p)
2320 if (*p == '/')
2321 *p = ':';
2322 p++;
2325 s_dirent.d_ino = cipb.dirInfo.ioDrDirID;
2326 /* value unimportant: non-zero for valid file */
2327 s_dirent.d_name = s_name;
2329 return &s_dirent;
2334 char *
2335 getwd (char *path)
2337 char mac_pathname[MAXPATHLEN+1];
2338 Str255 directory_name;
2339 OSErr errno;
2340 CInfoPBRec cipb;
2342 if (path_from_vol_dir_name (mac_pathname, 255, 0, 0, "\p") == 0)
2343 return NULL;
2345 if (mac_to_unix_pathname (mac_pathname, path, MAXPATHLEN+1) == 0)
2346 return 0;
2347 else
2348 return path;
2352 void
2353 initialize_applescript ()
2355 AEDesc null_desc;
2356 OSAError osaerror;
2358 /* if open fails, as_scripting_component is set to NULL. Its
2359 subsequent use in OSA calls will fail with badComponentInstance
2360 error. */
2361 as_scripting_component = OpenDefaultComponent (kOSAComponentType,
2362 kAppleScriptSubtype);
2364 null_desc.descriptorType = typeNull;
2365 null_desc.dataHandle = 0;
2366 osaerror = OSAMakeContext (as_scripting_component, &null_desc,
2367 kOSANullScript, &as_script_context);
2368 if (osaerror)
2369 as_script_context = kOSANullScript;
2370 /* use default context if create fails */
2374 void terminate_applescript()
2376 OSADispose (as_scripting_component, as_script_context);
2377 CloseComponent (as_scripting_component);
2381 /* Compile and execute the AppleScript SCRIPT and return the error
2382 status as function value. A zero is returned if compilation and
2383 execution is successful, in which case RESULT returns a pointer to
2384 a string containing the resulting script value. Otherwise, the Mac
2385 error code is returned and RESULT returns a pointer to an error
2386 string. In both cases the caller should deallocate the storage
2387 used by the string pointed to by RESULT if it is non-NULL. For
2388 documentation on the MacOS scripting architecture, see Inside
2389 Macintosh - Interapplication Communications: Scripting Components. */
2391 static long
2392 do_applescript (char *script, char **result)
2394 AEDesc script_desc, result_desc, error_desc;
2395 OSErr error;
2396 OSAError osaerror;
2397 long length;
2399 *result = 0;
2401 error = AECreateDesc (typeChar, script, strlen(script), &script_desc);
2402 if (error)
2403 return error;
2405 osaerror = OSADoScript (as_scripting_component, &script_desc, kOSANullScript,
2406 typeChar, kOSAModeNull, &result_desc);
2408 if (osaerror == errOSAScriptError)
2410 /* error executing AppleScript: retrieve error message */
2411 if (!OSAScriptError (as_scripting_component, kOSAErrorMessage, typeChar,
2412 &error_desc))
2414 HLock (error_desc.dataHandle);
2415 length = GetHandleSize(error_desc.dataHandle);
2416 *result = (char *) xmalloc (length + 1);
2417 if (*result)
2419 memcpy (*result, *(error_desc.dataHandle), length);
2420 *(*result + length) = '\0';
2422 HUnlock (error_desc.dataHandle);
2423 AEDisposeDesc (&error_desc);
2426 else if (osaerror == noErr) /* success: retrieve resulting script value */
2428 HLock (result_desc.dataHandle);
2429 length = GetHandleSize(result_desc.dataHandle);
2430 *result = (char *) xmalloc (length + 1);
2431 if (*result)
2433 memcpy (*result, *(result_desc.dataHandle), length);
2434 *(*result + length) = '\0';
2436 HUnlock (result_desc.dataHandle);
2439 AEDisposeDesc (&script_desc);
2440 AEDisposeDesc (&result_desc);
2442 return osaerror;
2446 DEFUN ("do-applescript", Fdo_applescript, Sdo_applescript, 1, 1, 0,
2447 "Compile and execute AppleScript SCRIPT and retrieve and return the\n\
2448 result. If compilation and execution are successful, the resulting script\n\
2449 value is returned as a string. Otherwise the function aborts and\n\
2450 displays the error message returned by the AppleScript scripting\n\
2451 component.")
2452 (script)
2453 Lisp_Object script;
2455 char *result, *temp;
2456 Lisp_Object lisp_result;
2457 long status;
2459 CHECK_STRING (script, 0);
2461 status = do_applescript (XSTRING (script)->data, &result);
2462 if (status)
2464 if (!result)
2465 error ("AppleScript error %ld", status);
2466 else
2468 /* Unfortunately only OSADoScript in do_applescript knows how
2469 how large the resulting script value or error message is
2470 going to be and therefore as caller memory must be
2471 deallocated here. It is necessary to free the error
2472 message before calling error to avoid a memory leak. */
2473 temp = (char *) alloca (strlen (result) + 1);
2474 strcpy (temp, result);
2475 xfree (result);
2476 error (temp);
2479 else
2481 lisp_result = build_string (result);
2482 xfree (result);
2483 return lisp_result;
2488 DEFUN ("mac-filename-to-unix", Fmac_filename_to_unix, Smac_filename_to_unix, 1,
2489 1, 0,
2490 "Convert Macintosh filename to Unix form.")
2491 (mac_filename)
2492 Lisp_Object mac_filename;
2494 char unix_filename[MAXPATHLEN+1];
2496 CHECK_STRING (mac_filename, 0);
2498 if (mac_to_unix_pathname(XSTRING (mac_filename)->data, unix_filename,
2499 MAXPATHLEN))
2500 return build_string (unix_filename);
2501 else
2502 return Qnil;
2506 DEFUN ("unix-filename-to-mac", Funix_filename_to_mac, Sunix_filename_to_mac, 1,
2507 1, 0,
2508 "Convert Unix filename to Mac form.")
2509 (unix_filename)
2510 Lisp_Object unix_filename;
2512 char mac_filename[MAXPATHLEN+1];
2514 CHECK_STRING (unix_filename, 0);
2516 if (unix_to_mac_pathname(XSTRING (unix_filename)->data, mac_filename,
2517 MAXPATHLEN))
2518 return build_string (mac_filename);
2519 else
2520 return Qnil;
2524 /* set interprogram-paste-function to mac-paste-function in mac-win.el
2525 to enable Emacs to obtain the contents of the Mac clipboard. */
2526 DEFUN ("mac-paste-function", Fmac_paste_function, Smac_paste_function, 0, 0, 0,
2527 "Return the contents of the Mac clipboard as a string.")
2530 Lisp_Object value;
2531 Handle my_handle;
2532 long scrap_offset, rc, i;
2534 my_handle = NewHandle (0); /* allocate 0-length data area */
2536 rc = GetScrap (my_handle, 'TEXT', &scrap_offset);
2537 if (rc < 0)
2538 return Qnil;
2540 HLock (my_handle);
2542 /* Emacs expects clipboard contents have Unix-style eol's */
2543 for (i = 0; i < rc; i++)
2544 if ((*my_handle)[i] == '\r')
2545 (*my_handle)[i] = '\n';
2547 value = make_string (*my_handle, rc);
2549 HUnlock (my_handle);
2551 DisposeHandle (my_handle);
2553 return value;
2557 /* set interprogram-cut-function to mac-cut-function in mac-win.el
2558 to enable Emacs to write the top of the kill-ring to the Mac clipboard. */
2559 DEFUN ("mac-cut-function", Fmac_cut_function, Smac_cut_function, 1, 2, 0,
2560 "Put the value of the string parameter to the Mac clipboard.")
2561 (value, push)
2562 Lisp_Object value, push;
2564 char *buf;
2565 int len, i;
2567 /* fixme: ignore the push flag for now */
2569 CHECK_STRING (value, 0);
2571 len = XSTRING (value)->size;
2572 buf = (char *) alloca (len);
2573 bcopy(XSTRING (value)->data, buf, len);
2575 /* convert to Mac-style eol's before sending to clipboard */
2576 for (i = 0; i < len; i++)
2577 if (buf[i] == '\n')
2578 buf[i] = '\r';
2580 ZeroScrap ();
2581 PutScrap (len, 'TEXT', buf);
2583 return Qnil;
2587 DEFUN ("x-selection-exists-p", Fx_selection_exists_p, Sx_selection_exists_p,
2588 0, 1, 0,
2589 "Whether there is an owner for the given X Selection.\n\
2590 The arg should be the name of the selection in question, typically one of\n\
2591 the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.\n\
2592 \(Those are literal upper-case symbol names, since that's what X expects.)\n\
2593 For convenience, the symbol nil is the same as `PRIMARY',\n\
2594 and t is the same as `SECONDARY'.")
2595 (selection)
2596 Lisp_Object selection;
2598 CHECK_SYMBOL (selection, 0);
2600 /* Return nil for PRIMARY and SECONDARY selections; for CLIPBOARD, check
2601 if the clipboard currently has valid text format contents. */
2603 if (EQ (selection, QCLIPBOARD))
2605 Lisp_Object val = Qnil;
2606 Lisp_Object value;
2607 Handle my_handle;
2608 long rc, scrap_offset;
2610 my_handle = NewHandle (0);
2612 rc = GetScrap (my_handle, 'TEXT', &scrap_offset);
2613 if (rc >= 0)
2614 val = Qt;
2616 DisposeHandle (my_handle);
2618 return val;
2620 return Qnil;
2624 void
2625 syms_of_mac ()
2627 QCLIPBOARD = intern ("CLIPBOARD");
2628 staticpro (&QCLIPBOARD);
2630 defsubr (&Smac_paste_function);
2631 defsubr (&Smac_cut_function);
2632 defsubr (&Sx_selection_exists_p);
2634 defsubr (&Sdo_applescript);
2635 defsubr (&Smac_filename_to_unix);
2636 defsubr (&Sunix_filename_to_mac);