Revision: miles@gnu.org--gnu-2004/emacs--cvs-trunk--0--patch-483
[bpt/emacs.git] / src / mac.c
CommitLineData
1a578e9b 1/* Unix emulation routines for GNU Emacs on the Mac OS.
e0f712ba 2 Copyright (C) 2000, 2001 Free Software Foundation, Inc.
1a578e9b
AC
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
20
e0f712ba 21/* Contributed by Andrew Choi (akochoi@mac.com). */
1a578e9b
AC
22
23#include <config.h>
24
25#include <stdio.h>
26#include <errno.h>
27#include <utime.h>
28#include <dirent.h>
1000788b 29#include <sys/types.h>
1a578e9b
AC
30#include <sys/stat.h>
31#include <string.h>
32#include <pwd.h>
49e7a2c0 33#include <grp.h>
1a578e9b 34#include <sys/param.h>
1000788b 35#include <stdlib.h>
2eb46b2d 36#include <fcntl.h>
1a578e9b
AC
37#if __MWERKS__
38#include <unistd.h>
39#endif
40
e0f712ba
AC
41#ifdef MAC_OSX
42#undef mktime
43#undef DEBUG
44#undef free
45#undef malloc
46#undef realloc
f00691a3 47#undef init_process
e0f712ba
AC
48#include <Carbon/Carbon.h>
49#undef free
50#define free unexec_free
51#undef malloc
52#define malloc unexec_malloc
53#undef realloc
54#define realloc unexec_realloc
f00691a3
AC
55#undef init_process
56#define init_process emacs_init_process
e0f712ba 57#else /* not MAC_OSX */
1a578e9b
AC
58#include <Files.h>
59#include <MacTypes.h>
60#include <TextUtils.h>
61#include <Folders.h>
62#include <Resources.h>
63#include <Aliases.h>
64#include <FixMath.h>
65#include <Timer.h>
66#include <OSA.h>
67#include <AppleScript.h>
e0f712ba
AC
68#include <Scrap.h>
69#endif /* not MAC_OSX */
1a578e9b
AC
70
71#include "lisp.h"
72#include "process.h"
73#include "sysselect.h"
74#include "systime.h"
75
76Lisp_Object QCLIPBOARD;
77
78/* An instance of the AppleScript component. */
79static ComponentInstance as_scripting_component;
80/* The single script context used for all script executions. */
81static OSAID as_script_context;
82
83
84/* When converting from Mac to Unix pathnames, /'s in folder names are
85 converted to :'s. This function, used in copying folder names,
86 performs a strncat and converts all character a to b in the copy of
87 the string s2 appended to the end of s1. */
88
89void
90string_cat_and_replace (char *s1, const char *s2, int n, char a, char b)
91{
92 int l1 = strlen (s1);
93 int l2 = strlen (s2);
94 char *p = s1 + l1;
95 int i;
7d0393cf 96
1a578e9b
AC
97 strncat (s1, s2, n);
98 for (i = 0; i < l2; i++)
99 {
100 if (*p == a)
101 *p = b;
102 p++;
103 }
104}
105
106
e0f712ba 107/* Convert a Mac pathname to Posix form. A Mac full pathname is one
1a578e9b 108 that does not begin with a ':' and contains at least one ':'. A Mac
7d0393cf 109 full pathname causes a '/' to be prepended to the Posix pathname.
1a578e9b
AC
110 The algorithm for the rest of the pathname is as follows:
111 For each segment between two ':',
112 if it is non-null, copy as is and then add a '/' at the end,
e0f712ba 113 otherwise, insert a "../" into the Posix pathname.
1a578e9b 114 Returns 1 if successful; 0 if fails. */
7d0393cf 115
1a578e9b 116int
60fe1161 117mac_to_posix_pathname (const char *mfn, char *ufn, int ufnbuflen)
1a578e9b
AC
118{
119 const char *p, *q, *pe;
7d0393cf 120
1a578e9b 121 strcpy (ufn, "");
7d0393cf 122
1a578e9b
AC
123 if (*mfn == '\0')
124 return 1;
7d0393cf 125
1a578e9b
AC
126 p = strchr (mfn, ':');
127 if (p != 0 && p != mfn) /* full pathname */
128 strcat (ufn, "/");
7d0393cf 129
1a578e9b
AC
130 p = mfn;
131 if (*p == ':')
132 p++;
133
134 pe = mfn + strlen (mfn);
135 while (p < pe)
136 {
137 q = strchr (p, ':');
138 if (q)
139 {
140 if (q == p)
141 { /* two consecutive ':' */
142 if (strlen (ufn) + 3 >= ufnbuflen)
143 return 0;
144 strcat (ufn, "../");
145 }
146 else
147 {
148 if (strlen (ufn) + (q - p) + 1 >= ufnbuflen)
149 return 0;
150 string_cat_and_replace (ufn, p, q - p, '/', ':');
151 strcat (ufn, "/");
152 }
153 p = q + 1;
154 }
155 else
156 {
157 if (strlen (ufn) + (pe - p) >= ufnbuflen)
158 return 0;
159 string_cat_and_replace (ufn, p, pe - p, '/', ':');
160 /* no separator for last one */
161 p = pe;
162 }
163 }
7d0393cf 164
1a578e9b
AC
165 return 1;
166}
167
168
169extern char *get_temp_dir_name ();
170
171
e0f712ba 172/* Convert a Posix pathname to Mac form. Approximately reverse of the
1a578e9b 173 above in algorithm. */
7d0393cf 174
1a578e9b 175int
60fe1161 176posix_to_mac_pathname (const char *ufn, char *mfn, int mfnbuflen)
1a578e9b
AC
177{
178 const char *p, *q, *pe;
179 char expanded_pathname[MAXPATHLEN+1];
7d0393cf 180
1a578e9b 181 strcpy (mfn, "");
7d0393cf 182
1a578e9b
AC
183 if (*ufn == '\0')
184 return 1;
185
186 p = ufn;
7d0393cf 187
1a578e9b
AC
188 /* Check for and handle volume names. Last comparison: strangely
189 somewhere "/.emacs" is passed. A temporary fix for now. */
190 if (*p == '/' && strchr (p+1, '/') == NULL && strcmp (p, "/.emacs") != 0)
191 {
192 if (strlen (p) + 1 > mfnbuflen)
193 return 0;
194 strcpy (mfn, p+1);
195 strcat (mfn, ":");
196 return 1;
197 }
198
199 /* expand to emacs dir found by init_emacs_passwd_dir */
200 if (strncmp (p, "~emacs/", 7) == 0)
201 {
202 struct passwd *pw = getpwnam ("emacs");
203 p += 7;
204 if (strlen (pw->pw_dir) + strlen (p) > MAXPATHLEN)
205 return 0;
206 strcpy (expanded_pathname, pw->pw_dir);
207 strcat (expanded_pathname, p);
208 p = expanded_pathname;
209 /* now p points to the pathname with emacs dir prefix */
210 }
211 else if (strncmp (p, "/tmp/", 5) == 0)
212 {
213 char *t = get_temp_dir_name ();
214 p += 5;
215 if (strlen (t) + strlen (p) > MAXPATHLEN)
216 return 0;
217 strcpy (expanded_pathname, t);
218 strcat (expanded_pathname, p);
219 p = expanded_pathname;
220 /* now p points to the pathname with emacs dir prefix */
7d0393cf 221 }
1a578e9b
AC
222 else if (*p != '/') /* relative pathname */
223 strcat (mfn, ":");
7d0393cf 224
1a578e9b
AC
225 if (*p == '/')
226 p++;
227
228 pe = p + strlen (p);
229 while (p < pe)
230 {
231 q = strchr (p, '/');
232 if (q)
233 {
234 if (q - p == 2 && *p == '.' && *(p+1) == '.')
235 {
236 if (strlen (mfn) + 1 >= mfnbuflen)
237 return 0;
238 strcat (mfn, ":");
239 }
240 else
241 {
242 if (strlen (mfn) + (q - p) + 1 >= mfnbuflen)
243 return 0;
244 string_cat_and_replace (mfn, p, q - p, ':', '/');
245 strcat (mfn, ":");
246 }
247 p = q + 1;
248 }
249 else
250 {
251 if (strlen (mfn) + (pe - p) >= mfnbuflen)
252 return 0;
253 string_cat_and_replace (mfn, p, pe - p, ':', '/');
254 p = pe;
255 }
256 }
7d0393cf 257
1a578e9b
AC
258 return 1;
259}
260
e0f712ba 261#ifndef MAC_OSX
1a578e9b
AC
262
263/* The following functions with "sys_" prefix are stubs to Unix
264 functions that have already been implemented by CW or MPW. The
265 calls to them in Emacs source course are #define'd to call the sys_
266 versions by the header files s-mac.h. In these stubs pathnames are
267 converted between their Unix and Mac forms. */
268
269
270/* Unix epoch is Jan 1, 1970 while Mac epoch is Jan 1, 1904: 66 years
271 + 17 leap days. These are for adjusting time values returned by
272 MacOS Toolbox functions. */
273
274#define MAC_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
275
276#ifdef __MWERKS__
e0f712ba 277#if __MSL__ < 0x6000
1a578e9b
AC
278/* CW Pro 5 epoch is Jan 1, 1900 (aaarghhhhh!); remember, 1900 is not
279 a leap year! This is for adjusting time_t values returned by MSL
280 functions. */
281#define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 70 + 17) * 24 * 60 * 60)
e0f712ba
AC
282#else /* __MSL__ >= 0x6000 */
283/* CW changes Pro 6 to follow Unix! */
1a578e9b 284#define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
e0f712ba 285#endif /* __MSL__ >= 0x6000 */
1a578e9b
AC
286#elif __MRC__
287/* MPW library functions follow Unix (confused?). */
288#define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
e0f712ba 289#else /* not __MRC__ */
1a578e9b 290You lose!!!
e0f712ba 291#endif /* not __MRC__ */
1a578e9b
AC
292
293
294/* Define our own stat function for both MrC and CW. The reason for
295 doing this: "stat" is both the name of a struct and function name:
296 can't use the same trick like that for sys_open, sys_close, etc. to
297 redirect Emacs's calls to our own version that converts Unix style
298 filenames to Mac style filename because all sorts of compilation
299 errors will be generated if stat is #define'd to be sys_stat. */
300
301int
302stat_noalias (const char *path, struct stat *buf)
303{
304 char mac_pathname[MAXPATHLEN+1];
305 CInfoPBRec cipb;
306
60fe1161 307 if (posix_to_mac_pathname (path, mac_pathname, MAXPATHLEN+1) == 0)
1a578e9b
AC
308 return -1;
309
310 c2pstr (mac_pathname);
311 cipb.hFileInfo.ioNamePtr = mac_pathname;
312 cipb.hFileInfo.ioVRefNum = 0;
313 cipb.hFileInfo.ioDirID = 0;
314 cipb.hFileInfo.ioFDirIndex = 0;
315 /* set to 0 to get information about specific dir or file */
7d0393cf 316
1a578e9b
AC
317 errno = PBGetCatInfo (&cipb, false);
318 if (errno == -43) /* -43: fnfErr defined in Errors.h */
319 errno = ENOENT;
320 if (errno != noErr)
321 return -1;
322
323 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* bit 4 = 1 for directories */
324 {
325 buf->st_mode = S_IFDIR | S_IREAD | S_IEXEC;
7d0393cf 326
1a578e9b
AC
327 if (!(cipb.hFileInfo.ioFlAttrib & 0x1))
328 buf->st_mode |= S_IWRITE; /* bit 1 = 1 for locked files/directories */
329 buf->st_ino = cipb.dirInfo.ioDrDirID;
330 buf->st_dev = cipb.dirInfo.ioVRefNum;
331 buf->st_size = cipb.dirInfo.ioDrNmFls;
332 /* size of dir = number of files and dirs */
333 buf->st_atime
334 = buf->st_mtime
335 = cipb.dirInfo.ioDrMdDat - MAC_UNIX_EPOCH_DIFF;
336 buf->st_ctime = cipb.dirInfo.ioDrCrDat - MAC_UNIX_EPOCH_DIFF;
337 }
338 else
339 {
340 buf->st_mode = S_IFREG | S_IREAD;
341 if (!(cipb.hFileInfo.ioFlAttrib & 0x1))
342 buf->st_mode |= S_IWRITE; /* bit 1 = 1 for locked files/directories */
343 if (cipb.hFileInfo.ioFlFndrInfo.fdType == 'APPL')
344 buf->st_mode |= S_IEXEC;
345 buf->st_ino = cipb.hFileInfo.ioDirID;
346 buf->st_dev = cipb.hFileInfo.ioVRefNum;
347 buf->st_size = cipb.hFileInfo.ioFlLgLen;
348 buf->st_atime
349 = buf->st_mtime
350 = cipb.hFileInfo.ioFlMdDat - MAC_UNIX_EPOCH_DIFF;
351 buf->st_ctime = cipb.hFileInfo.ioFlCrDat - MAC_UNIX_EPOCH_DIFF;
352 }
353
354 if (cipb.hFileInfo.ioFlFndrInfo.fdFlags & 0x8000)
355 {
356 /* identify alias files as symlinks */
1a578e9b 357 buf->st_mode &= ~S_IFREG;
3b6944ed 358 buf->st_mode |= S_IFLNK;
1a578e9b
AC
359 }
360
361 buf->st_nlink = 1;
362 buf->st_uid = getuid ();
363 buf->st_gid = getgid ();
364 buf->st_rdev = 0;
365
366 return 0;
367}
368
369
370int
371lstat (const char *path, struct stat *buf)
372{
373 int result;
374 char true_pathname[MAXPATHLEN+1];
375
376 /* Try looking for the file without resolving aliases first. */
377 if ((result = stat_noalias (path, buf)) >= 0)
378 return result;
379
380 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
381 return -1;
7d0393cf 382
1a578e9b
AC
383 return stat_noalias (true_pathname, buf);
384}
385
386
387int
388stat (const char *path, struct stat *sb)
389{
390 int result;
7d0393cf 391 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
1a578e9b 392 int len;
7d0393cf 393
3b6944ed
AC
394 if ((result = stat_noalias (path, sb)) >= 0 &&
395 ! (sb->st_mode & S_IFLNK))
1a578e9b
AC
396 return result;
397
398 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
399 return -1;
7d0393cf 400
1a578e9b
AC
401 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
402 if (len > -1)
403 {
404 fully_resolved_name[len] = '\0';
405 /* in fact our readlink terminates strings */
406 return lstat (fully_resolved_name, sb);
407 }
408 else
409 return lstat (true_pathname, sb);
410}
411
412
413#if __MRC__
414/* CW defines fstat in stat.mac.c while MPW does not provide this
415 function. Without the information of how to get from a file
416 descriptor in MPW StdCLib to a Mac OS file spec, it should be hard
417 to implement this function. Fortunately, there is only one place
418 where this function is called in our configuration: in fileio.c,
419 where only the st_dev and st_ino fields are used to determine
420 whether two fildes point to different i-nodes to prevent copying
421 a file onto itself equal. What we have here probably needs
422 improvement. */
423
424int
425fstat (int fildes, struct stat *buf)
426{
427 buf->st_dev = 0;
428 buf->st_ino = fildes;
429 buf->st_mode = S_IFREG; /* added by T.I. for the copy-file */
430 return 0; /* success */
431}
432#endif /* __MRC__ */
433
434
1a578e9b
AC
435int
436mkdir (const char *dirname, int mode)
437{
438#pragma unused(mode)
439
440 HFileParam hfpb;
441 char true_pathname[MAXPATHLEN+1], mac_pathname[MAXPATHLEN+1];
7d0393cf 442
1a578e9b
AC
443 if (find_true_pathname (dirname, true_pathname, MAXPATHLEN+1) == -1)
444 return -1;
7d0393cf 445
60fe1161 446 if (posix_to_mac_pathname (true_pathname, mac_pathname, MAXPATHLEN+1) == 0)
1a578e9b
AC
447 return -1;
448
449 c2pstr (mac_pathname);
450 hfpb.ioNamePtr = mac_pathname;
451 hfpb.ioVRefNum = 0; /* ignored unless name is invalid */
452 hfpb.ioDirID = 0; /* parent is the root */
7d0393cf 453
1a578e9b
AC
454 errno = PBDirCreate ((HParmBlkPtr) &hfpb, false);
455 /* just return the Mac OSErr code for now */
456 return errno == noErr ? 0 : -1;
457}
458
459
460#undef rmdir
461sys_rmdir (const char *dirname)
462{
463 HFileParam hfpb;
464 char mac_pathname[MAXPATHLEN+1];
7d0393cf 465
60fe1161 466 if (posix_to_mac_pathname (dirname, mac_pathname, MAXPATHLEN+1) == 0)
1a578e9b
AC
467 return -1;
468
469 c2pstr (mac_pathname);
470 hfpb.ioNamePtr = mac_pathname;
471 hfpb.ioVRefNum = 0; /* ignored unless name is invalid */
472 hfpb.ioDirID = 0; /* parent is the root */
7d0393cf 473
1a578e9b
AC
474 errno = PBHDelete ((HParmBlkPtr) &hfpb, false);
475 return errno == noErr ? 0 : -1;
476}
477
478
479#ifdef __MRC__
480/* No implementation yet. */
481int
482execvp (const char *path, ...)
483{
484 return -1;
485}
486#endif /* __MRC__ */
487
488
489int
490utime (const char *path, const struct utimbuf *times)
491{
7d0393cf 492 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
1a578e9b
AC
493 int len;
494 char mac_pathname[MAXPATHLEN+1];
495 CInfoPBRec cipb;
7d0393cf 496
1a578e9b
AC
497 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
498 return -1;
7d0393cf 499
1a578e9b
AC
500 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
501 if (len > -1)
502 fully_resolved_name[len] = '\0';
503 else
504 strcpy (fully_resolved_name, true_pathname);
505
60fe1161 506 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
1a578e9b
AC
507 return -1;
508
509 c2pstr (mac_pathname);
510 cipb.hFileInfo.ioNamePtr = mac_pathname;
511 cipb.hFileInfo.ioVRefNum = 0;
512 cipb.hFileInfo.ioDirID = 0;
7d0393cf 513 cipb.hFileInfo.ioFDirIndex = 0;
1a578e9b 514 /* set to 0 to get information about specific dir or file */
7d0393cf 515
1a578e9b
AC
516 errno = PBGetCatInfo (&cipb, false);
517 if (errno != noErr)
518 return -1;
519
520 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* bit 4 = 1 for directories */
521 {
522 if (times)
523 cipb.dirInfo.ioDrMdDat = times->modtime + MAC_UNIX_EPOCH_DIFF;
524 else
525 GetDateTime (&cipb.dirInfo.ioDrMdDat);
526 }
527 else
528 {
529 if (times)
530 cipb.hFileInfo.ioFlMdDat = times->modtime + MAC_UNIX_EPOCH_DIFF;
531 else
532 GetDateTime (&cipb.hFileInfo.ioFlMdDat);
533 }
534
535 errno = PBSetCatInfo (&cipb, false);
536 return errno == noErr ? 0 : -1;
537}
538
539
540#ifndef F_OK
541#define F_OK 0
542#endif
543#ifndef X_OK
544#define X_OK 1
545#endif
546#ifndef W_OK
547#define W_OK 2
548#endif
549
550/* Like stat, but test for access mode in hfpb.ioFlAttrib */
551int
552access (const char *path, int mode)
553{
7d0393cf 554 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
1a578e9b
AC
555 int len;
556 char mac_pathname[MAXPATHLEN+1];
557 CInfoPBRec cipb;
7d0393cf 558
1a578e9b
AC
559 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
560 return -1;
7d0393cf 561
1a578e9b
AC
562 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
563 if (len > -1)
564 fully_resolved_name[len] = '\0';
565 else
566 strcpy (fully_resolved_name, true_pathname);
567
60fe1161 568 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
1a578e9b
AC
569 return -1;
570
571 c2pstr (mac_pathname);
572 cipb.hFileInfo.ioNamePtr = mac_pathname;
573 cipb.hFileInfo.ioVRefNum = 0;
574 cipb.hFileInfo.ioDirID = 0;
575 cipb.hFileInfo.ioFDirIndex = 0;
576 /* set to 0 to get information about specific dir or file */
7d0393cf 577
1a578e9b
AC
578 errno = PBGetCatInfo (&cipb, false);
579 if (errno != noErr)
580 return -1;
581
582 if (mode == F_OK) /* got this far, file exists */
583 return 0;
584
585 if (mode & X_OK)
586 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* path refers to a directory */
587 return 0;
588 else
589 {
590 if (cipb.hFileInfo.ioFlFndrInfo.fdType == 'APPL')
591 return 0;
592 else
593 return -1;
594 }
595
596 if (mode & W_OK)
597 return (cipb.hFileInfo.ioFlAttrib & 0x1) ? -1 : 0;
598 /* don't allow if lock bit is on */
599
600 return -1;
601}
602
603
604#define DEV_NULL_FD 0x10000
605
606#undef open
607int
608sys_open (const char *path, int oflag)
609{
7d0393cf 610 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
1a578e9b
AC
611 int len;
612 char mac_pathname[MAXPATHLEN+1];
7d0393cf 613
1a578e9b
AC
614 if (strcmp (path, "/dev/null") == 0)
615 return DEV_NULL_FD; /* some bogus fd to be ignored in write */
7d0393cf 616
1a578e9b
AC
617 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
618 return -1;
7d0393cf 619
1a578e9b
AC
620 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
621 if (len > -1)
622 fully_resolved_name[len] = '\0';
623 else
624 strcpy (fully_resolved_name, true_pathname);
625
60fe1161 626 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
1a578e9b
AC
627 return -1;
628 else
629 {
630#ifdef __MRC__
3b6944ed
AC
631 int res = open (mac_pathname, oflag);
632 /* if (oflag == O_WRONLY || oflag == O_RDWR) */
633 if (oflag & O_CREAT)
1a578e9b 634 fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
3b6944ed 635 return res;
e0f712ba 636#else /* not __MRC__ */
1a578e9b 637 return open (mac_pathname, oflag);
e0f712ba 638#endif /* not __MRC__ */
1a578e9b
AC
639 }
640}
641
642
643#undef creat
644int
645sys_creat (const char *path, mode_t mode)
646{
7d0393cf 647 char true_pathname[MAXPATHLEN+1];
1a578e9b
AC
648 int len;
649 char mac_pathname[MAXPATHLEN+1];
7d0393cf 650
1a578e9b
AC
651 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
652 return -1;
653
60fe1161 654 if (!posix_to_mac_pathname (true_pathname, mac_pathname, MAXPATHLEN+1))
1a578e9b
AC
655 return -1;
656 else
657 {
658#ifdef __MRC__
659 int result = creat (mac_pathname);
660 fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
661 return result;
e0f712ba 662#else /* not __MRC__ */
1a578e9b 663 return creat (mac_pathname, mode);
e0f712ba 664#endif /* not __MRC__ */
1a578e9b
AC
665 }
666}
667
668
669#undef unlink
670int
671sys_unlink (const char *path)
672{
7d0393cf 673 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
1a578e9b
AC
674 int len;
675 char mac_pathname[MAXPATHLEN+1];
7d0393cf 676
1a578e9b
AC
677 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
678 return -1;
7d0393cf 679
1a578e9b
AC
680 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
681 if (len > -1)
682 fully_resolved_name[len] = '\0';
683 else
684 strcpy (fully_resolved_name, true_pathname);
685
60fe1161 686 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
1a578e9b
AC
687 return -1;
688 else
689 return unlink (mac_pathname);
690}
691
692
693#undef read
694int
695sys_read (int fildes, char *buf, int count)
696{
697 if (fildes == 0) /* this should not be used for console input */
698 return -1;
699 else
e0f712ba 700#if __MSL__ >= 0x6000
1a578e9b
AC
701 return _read (fildes, buf, count);
702#else
703 return read (fildes, buf, count);
704#endif
705}
706
707
708#undef write
709int
710sys_write (int fildes, const char *buf, int count)
711{
712 if (fildes == DEV_NULL_FD)
713 return count;
714 else
e0f712ba 715#if __MSL__ >= 0x6000
1a578e9b
AC
716 return _write (fildes, buf, count);
717#else
718 return write (fildes, buf, count);
719#endif
720}
721
722
723#undef rename
724int
725sys_rename (const char * old_name, const char * new_name)
726{
727 char true_old_pathname[MAXPATHLEN+1], true_new_pathname[MAXPATHLEN+1];
7d0393cf 728 char fully_resolved_old_name[MAXPATHLEN+1];
1a578e9b
AC
729 int len;
730 char mac_old_name[MAXPATHLEN+1], mac_new_name[MAXPATHLEN+1];
7d0393cf 731
1a578e9b
AC
732 if (find_true_pathname (old_name, true_old_pathname, MAXPATHLEN+1) == -1)
733 return -1;
7d0393cf 734
1a578e9b
AC
735 len = readlink (true_old_pathname, fully_resolved_old_name, MAXPATHLEN);
736 if (len > -1)
737 fully_resolved_old_name[len] = '\0';
738 else
739 strcpy (fully_resolved_old_name, true_old_pathname);
740
741 if (find_true_pathname (new_name, true_new_pathname, MAXPATHLEN+1) == -1)
742 return -1;
7d0393cf 743
1a578e9b
AC
744 if (strcmp (fully_resolved_old_name, true_new_pathname) == 0)
745 return 0;
746
60fe1161 747 if (!posix_to_mac_pathname (fully_resolved_old_name,
1a578e9b
AC
748 mac_old_name,
749 MAXPATHLEN+1))
750 return -1;
7d0393cf 751
60fe1161 752 if (!posix_to_mac_pathname(true_new_pathname, mac_new_name, MAXPATHLEN+1))
1a578e9b
AC
753 return -1;
754
755 /* If a file with new_name already exists, rename deletes the old
756 file in Unix. CW version fails in these situation. So we add a
757 call to unlink here. */
758 (void) unlink (mac_new_name);
7d0393cf 759
1a578e9b
AC
760 return rename (mac_old_name, mac_new_name);
761}
762
763
764#undef fopen
765extern FILE *fopen (const char *name, const char *mode);
766FILE *
767sys_fopen (const char *name, const char *mode)
768{
7d0393cf 769 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
1a578e9b
AC
770 int len;
771 char mac_pathname[MAXPATHLEN+1];
7d0393cf 772
1a578e9b
AC
773 if (find_true_pathname (name, true_pathname, MAXPATHLEN+1) == -1)
774 return 0;
7d0393cf 775
1a578e9b
AC
776 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
777 if (len > -1)
778 fully_resolved_name[len] = '\0';
779 else
780 strcpy (fully_resolved_name, true_pathname);
781
60fe1161 782 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
1a578e9b
AC
783 return 0;
784 else
785 {
786#ifdef __MRC__
787 if (mode[0] == 'w' || mode[0] == 'a')
788 fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
e0f712ba 789#endif /* not __MRC__ */
1a578e9b
AC
790 return fopen (mac_pathname, mode);
791 }
792}
793
794
795#include <Events.h>
796
797long target_ticks = 0;
798
799#ifdef __MRC__
800__sigfun alarm_signal_func = (__sigfun) 0;
801#elif __MWERKS__
802__signal_func_ptr alarm_signal_func = (__signal_func_ptr) 0;
e0f712ba 803#else /* not __MRC__ and not __MWERKS__ */
1a578e9b 804You lose!!!
e0f712ba 805#endif /* not __MRC__ and not __MWERKS__ */
1a578e9b
AC
806
807
808/* These functions simulate SIG_ALRM. The stub for function signal
809 stores the signal handler function in alarm_signal_func if a
810 SIG_ALRM is encountered. check_alarm is called in XTread_socket,
811 which emacs calls periodically. A pending alarm is represented by
812 a non-zero target_ticks value. check_alarm calls the handler
813 function pointed to by alarm_signal_func if one has been set up and
814 an alarm is pending. */
815
816void
817check_alarm ()
818{
819 if (target_ticks && TickCount () > target_ticks)
820 {
821 target_ticks = 0;
822 if (alarm_signal_func)
823 (*alarm_signal_func)(SIGALRM);
824 }
825}
826
827
828int
e0f712ba 829select (n, rfds, wfds, efds, timeout)
1a578e9b
AC
830 int n;
831 SELECT_TYPE *rfds;
832 SELECT_TYPE *wfds;
833 SELECT_TYPE *efds;
834 struct timeval *timeout;
835{
e0f712ba
AC
836#ifdef TARGET_API_MAC_CARBON
837 return 1;
838#else /* not TARGET_API_MAC_CARBON */
1a578e9b
AC
839 EMACS_TIME end_time, now;
840 EventRecord e;
1a578e9b
AC
841
842 /* Can only handle wait for keyboard input. */
843 if (n > 1 || wfds || efds)
844 return -1;
845
846 EMACS_GET_TIME (end_time);
847 EMACS_ADD_TIME (end_time, end_time, *timeout);
7d0393cf 848
1a578e9b
AC
849 do
850 {
851 /* Also return true if an event other than a keyDown has
852 occurred. This causes kbd_buffer_get_event in keyboard.c to
853 call read_avail_input which in turn calls XTread_socket to
854 poll for these events. Otherwise these never get processed
855 except but a very slow poll timer. */
856 if (FD_ISSET (0, rfds) && EventAvail (everyEvent, &e))
857 return 1;
858
859 /* Also check movement of the mouse. */
860 {
861 Point mouse_pos;
862 static Point old_mouse_pos = {-1, -1};
7d0393cf 863
1a578e9b
AC
864 GetMouse (&mouse_pos);
865 if (!EqualPt (mouse_pos, old_mouse_pos))
866 {
867 old_mouse_pos = mouse_pos;
868 return 1;
869 }
870 }
7d0393cf 871
e0f712ba
AC
872 WaitNextEvent (0, &e, 1UL, NULL); /* Accept no event; wait 1
873 tic. by T.I. */
7d0393cf 874
1a578e9b
AC
875 EMACS_GET_TIME (now);
876 EMACS_SUB_TIME (now, end_time, now);
877 }
878 while (!EMACS_TIME_NEG_P (now));
879
880 return 0;
e0f712ba 881#endif /* not TARGET_API_MAC_CARBON */
1a578e9b
AC
882}
883
884
885/* Called in sys_select to wait for an alarm signal to arrive. */
886
887int
888pause ()
889{
fa0b4c14
AC
890 EventRecord e;
891 unsigned long tick;
7d0393cf 892
1a578e9b
AC
893 if (!target_ticks) /* no alarm pending */
894 return -1;
895
e0f712ba
AC
896 if ((tick = TickCount ()) < target_ticks)
897 WaitNextEvent (0, &e, target_ticks - tick, NULL); /* Accept no event;
898 just wait. by T.I. */
7d0393cf 899
1a578e9b
AC
900 target_ticks = 0;
901 if (alarm_signal_func)
902 (*alarm_signal_func)(SIGALRM);
7d0393cf 903
1a578e9b
AC
904 return 0;
905}
906
907
908int
909alarm (int seconds)
910{
911 long remaining = target_ticks ? (TickCount () - target_ticks) / 60 : 0;
7d0393cf 912
1a578e9b 913 target_ticks = seconds ? TickCount () + 60 * seconds : 0;
7d0393cf 914
1a578e9b
AC
915 return (remaining < 0) ? 0 : (unsigned int) remaining;
916}
917
918
919#undef signal
920#ifdef __MRC__
921extern __sigfun signal (int signal, __sigfun signal_func);
922__sigfun
923sys_signal (int signal_num, __sigfun signal_func)
924#elif __MWERKS__
925extern __signal_func_ptr signal (int signal, __signal_func_ptr signal_func);
926__signal_func_ptr
927sys_signal (int signal_num, __signal_func_ptr signal_func)
e0f712ba 928#else /* not __MRC__ and not __MWERKS__ */
1a578e9b 929 You lose!!!
e0f712ba 930#endif /* not __MRC__ and not __MWERKS__ */
1a578e9b
AC
931{
932 if (signal_num != SIGALRM)
933 return signal (signal_num, signal_func);
934 else
935 {
936#ifdef __MRC__
7d0393cf 937 __sigfun old_signal_func;
1a578e9b 938#elif __MWERKS__
7d0393cf 939 __signal_func_ptr old_signal_func;
1a578e9b
AC
940#else
941 You lose!!!
942#endif
943 old_signal_func = alarm_signal_func;
944 alarm_signal_func = signal_func;
945 return old_signal_func;
946 }
947}
948
949
950/* gettimeofday should return the amount of time (in a timeval
951 structure) since midnight today. The toolbox function Microseconds
952 returns the number of microseconds (in a UnsignedWide value) since
953 the machine was booted. Also making this complicated is WideAdd,
954 WideSubtract, etc. take wide values. */
955
956int
957gettimeofday (tp)
958 struct timeval *tp;
959{
960 static inited = 0;
961 static wide wall_clock_at_epoch, clicks_at_epoch;
962 UnsignedWide uw_microseconds;
963 wide w_microseconds;
964 time_t sys_time (time_t *);
965
966 /* If this function is called for the first time, record the number
967 of seconds since midnight and the number of microseconds since
968 boot at the time of this first call. */
969 if (!inited)
970 {
971 time_t systime;
972 inited = 1;
973 systime = sys_time (NULL);
974 /* Store microseconds since midnight in wall_clock_at_epoch. */
975 WideMultiply (systime, 1000000L, &wall_clock_at_epoch);
976 Microseconds (&uw_microseconds);
977 /* Store microseconds since boot in clicks_at_epoch. */
978 clicks_at_epoch.hi = uw_microseconds.hi;
979 clicks_at_epoch.lo = uw_microseconds.lo;
980 }
981
982 /* Get time since boot */
983 Microseconds (&uw_microseconds);
7d0393cf 984
1a578e9b
AC
985 /* Convert to time since midnight*/
986 w_microseconds.hi = uw_microseconds.hi;
987 w_microseconds.lo = uw_microseconds.lo;
988 WideSubtract (&w_microseconds, &clicks_at_epoch);
989 WideAdd (&w_microseconds, &wall_clock_at_epoch);
990 tp->tv_sec = WideDivide (&w_microseconds, 1000000L, &tp->tv_usec);
991
992 return 0;
993}
994
995
996#ifdef __MRC__
997unsigned int
998sleep (unsigned int seconds)
999{
bc04fb2c 1000 unsigned long time_up;
fa0b4c14
AC
1001 EventRecord e;
1002
bc04fb2c
AC
1003 time_up = TickCount () + seconds * 60;
1004 while (TickCount () < time_up)
1005 {
1006 /* Accept no event; just wait. by T.I. */
1007 WaitNextEvent (0, &e, 30, NULL);
1008 }
1a578e9b 1009
1a578e9b
AC
1010 return (0);
1011}
1012#endif /* __MRC__ */
1013
1014
1015/* The time functions adjust time values according to the difference
1016 between the Unix and CW epoches. */
1017
1018#undef gmtime
1019extern struct tm *gmtime (const time_t *);
1020struct tm *
1021sys_gmtime (const time_t *timer)
1022{
1023 time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
7d0393cf 1024
1a578e9b
AC
1025 return gmtime (&unix_time);
1026}
1027
1028
1029#undef localtime
1030extern struct tm *localtime (const time_t *);
1031struct tm *
1032sys_localtime (const time_t *timer)
1033{
e0f712ba 1034#if __MSL__ >= 0x6000
1a578e9b
AC
1035 time_t unix_time = *timer;
1036#else
1037 time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
1038#endif
7d0393cf 1039
1a578e9b
AC
1040 return localtime (&unix_time);
1041}
1042
1043
1044#undef ctime
1045extern char *ctime (const time_t *);
1046char *
1047sys_ctime (const time_t *timer)
1048{
e0f712ba 1049#if __MSL__ >= 0x6000
1a578e9b
AC
1050 time_t unix_time = *timer;
1051#else
1052 time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
1053#endif
7d0393cf 1054
1a578e9b
AC
1055 return ctime (&unix_time);
1056}
1057
1058
1059#undef time
1060extern time_t time (time_t *);
1061time_t
1062sys_time (time_t *timer)
1063{
e0f712ba 1064#if __MSL__ >= 0x6000
1a578e9b
AC
1065 time_t mac_time = time (NULL);
1066#else
1067 time_t mac_time = time (NULL) - CW_OR_MPW_UNIX_EPOCH_DIFF;
1068#endif
1069
1070 if (timer)
1071 *timer = mac_time;
7d0393cf 1072
1a578e9b
AC
1073 return mac_time;
1074}
1075
1076
1077/* MPW strftime broken for "%p" format */
1078#ifdef __MRC__
1079#undef strftime
1080#include <time.h>
1081size_t
1082sys_strftime (char * s, size_t maxsize, const char * format,
1083 const struct tm * timeptr)
1084{
1085 if (strcmp (format, "%p") == 0)
1086 {
1087 if (maxsize < 3)
1088 return 0;
1089 if (timeptr->tm_hour < 12)
1090 {
1091 strcpy (s, "AM");
1092 return 2;
1093 }
1094 else
1095 {
1096 strcpy (s, "PM");
1097 return 2;
1098 }
1099 }
1100 else
1101 return strftime (s, maxsize, format, timeptr);
1102}
1103#endif /* __MRC__ */
1104
1105
1106/* no subprocesses, empty wait */
1107
1108int
1109wait (int pid)
1110{
1111 return 0;
1112}
1113
1114
1115void
1116croak (char *badfunc)
1117{
1118 printf ("%s not yet implemented\r\n", badfunc);
1119 exit (1);
1120}
1121
1122
1123char *
1124index (const char * str, int chr)
1125{
1126 return strchr (str, chr);
1127}
1128
1129
1130char *
1131mktemp (char *template)
1132{
1133 int len, k;
1134 static seqnum = 0;
7d0393cf 1135
1a578e9b
AC
1136 len = strlen (template);
1137 k = len - 1;
1138 while (k >= 0 && template[k] == 'X')
1139 k--;
7d0393cf 1140
1a578e9b 1141 k++; /* make k index of first 'X' */
7d0393cf 1142
1a578e9b
AC
1143 if (k < len)
1144 {
1145 /* Zero filled, number of digits equal to the number of X's. */
1146 sprintf (&template[k], "%0*d", len-k, seqnum++);
7d0393cf 1147
1a578e9b
AC
1148 return template;
1149 }
1150 else
7d0393cf 1151 return 0;
1a578e9b
AC
1152}
1153
1154
1155/* Emulate getpwuid, getpwnam and others. */
1156
1157#define PASSWD_FIELD_SIZE 256
1158
1159static char my_passwd_name[PASSWD_FIELD_SIZE];
1160static char my_passwd_dir[MAXPATHLEN+1];
1161
7d0393cf 1162static struct passwd my_passwd =
1a578e9b
AC
1163{
1164 my_passwd_name,
1165 my_passwd_dir,
1166};
1167
49e7a2c0
LH
1168static struct group my_group =
1169{
1170 /* There are no groups on the mac, so we just return "root" as the
1171 group name. */
1172 "root",
1173};
1174
1a578e9b
AC
1175
1176/* Initialized by main () in macterm.c to pathname of emacs directory. */
1177
1178char emacs_passwd_dir[MAXPATHLEN+1];
1179
1180char *
1181getwd (char *);
1182
1183void
1184init_emacs_passwd_dir ()
1185{
1186 int found = false;
1187
1188 if (getwd (emacs_passwd_dir) && getwd (my_passwd_dir))
1189 {
1190 /* Need pathname of first ancestor that begins with "emacs"
1191 since Mac emacs application is somewhere in the emacs-*
1192 tree. */
1193 int len = strlen (emacs_passwd_dir);
1194 int j = len - 1;
1195 /* j points to the "/" following the directory name being
1196 compared. */
1197 int i = j - 1;
1198 while (i >= 0 && !found)
1199 {
1200 while (i >= 0 && emacs_passwd_dir[i] != '/')
1201 i--;
1202 if (emacs_passwd_dir[i] == '/' && i+5 < len)
1203 found = (strncmp (&(emacs_passwd_dir[i+1]), "emacs", 5) == 0);
1204 if (found)
1205 emacs_passwd_dir[j+1] = '\0';
1206 else
1207 {
1208 j = i;
1209 i = j - 1;
1210 }
1211 }
1212 }
7d0393cf 1213
1a578e9b
AC
1214 if (!found)
1215 {
1216 /* Setting to "/" probably won't work but set it to something
1217 anyway. */
1218 strcpy (emacs_passwd_dir, "/");
1219 strcpy (my_passwd_dir, "/");
1220 }
1221}
1222
1223
7d0393cf 1224static struct passwd emacs_passwd =
1a578e9b
AC
1225{
1226 "emacs",
1227 emacs_passwd_dir,
1228};
1229
1230static int my_passwd_inited = 0;
1231
1232
1233static void
1234init_my_passwd ()
1235{
1236 char **owner_name;
1237
1238 /* Note: my_passwd_dir initialized in int_emacs_passwd_dir to
1239 directory where Emacs was started. */
1240
1241 owner_name = (char **) GetResource ('STR ',-16096);
1242 if (owner_name)
1243 {
1244 HLock (owner_name);
1245 BlockMove ((unsigned char *) *owner_name,
1246 (unsigned char *) my_passwd_name,
1247 *owner_name[0]+1);
1248 HUnlock (owner_name);
1249 p2cstr ((unsigned char *) my_passwd_name);
1250 }
1251 else
1252 my_passwd_name[0] = 0;
1253}
1254
1255
1256struct passwd *
1257getpwuid (uid_t uid)
1258{
1259 if (!my_passwd_inited)
7d0393cf 1260 {
1a578e9b
AC
1261 init_my_passwd ();
1262 my_passwd_inited = 1;
1263 }
7d0393cf 1264
1a578e9b
AC
1265 return &my_passwd;
1266}
1267
1268
49e7a2c0
LH
1269struct group *
1270getgrgid (gid_t gid)
1271{
1272 return &my_group;
1273}
1274
1275
1a578e9b
AC
1276struct passwd *
1277getpwnam (const char *name)
1278{
1279 if (strcmp (name, "emacs") == 0)
1280 return &emacs_passwd;
1281
1282 if (!my_passwd_inited)
7d0393cf 1283 {
1a578e9b
AC
1284 init_my_passwd ();
1285 my_passwd_inited = 1;
1286 }
7d0393cf 1287
1a578e9b
AC
1288 return &my_passwd;
1289}
1290
1291
1292/* The functions fork, kill, sigsetmask, sigblock, request_sigio,
1293 setpgrp, setpriority, and unrequest_sigio are defined to be empty
1294 as in msdos.c. */
1295
1296
1297int
1298fork ()
1299{
1300 return -1;
1301}
1302
1303
1304int
1305kill (int x, int y)
1306{
1307 return -1;
1308}
1309
1310
1311void
1312sys_subshell ()
1313{
1314 error ("Can't spawn subshell");
1315}
1316
1317
1318int
1319sigsetmask (int x)
1320{
1321 return 0;
1322}
1323
1324
1325int
1326sigblock (int mask)
1327{
1328 return 0;
7d0393cf 1329}
1a578e9b
AC
1330
1331
1332void
1333request_sigio (void)
1334{
1335}
1336
1337
1338void
1339unrequest_sigio (void)
1340{
1341}
1342
1343
1344int
1345setpgrp ()
1346{
1347 return 0;
1348}
1349
1350
1351/* No pipes yet. */
1352
1353int
1354pipe (int _fildes[2])
1355{
1356 errno = EACCES;
1357 return -1;
1358}
1359
1360
1361/* Hard and symbolic links. */
1362
1363int
1364symlink (const char *name1, const char *name2)
1365{
1366 errno = ENOENT;
1367 return -1;
1368}
1369
1370
1371int
1372link (const char *name1, const char *name2)
1373{
1374 errno = ENOENT;
1375 return -1;
1376}
1377
e0f712ba 1378#endif /* ! MAC_OSX */
1a578e9b
AC
1379
1380/* Determine the path name of the file specified by VREFNUM, DIRID,
1381 and NAME and place that in the buffer PATH of length
1382 MAXPATHLEN. */
1383int
1384path_from_vol_dir_name (char *path, int man_path_len, short vol_ref_num,
1385 long dir_id, ConstStr255Param name)
1386{
1387 Str255 dir_name;
1388 CInfoPBRec cipb;
1389 OSErr err;
1390
1391 if (strlen (name) > man_path_len)
1392 return 0;
1393
1394 memcpy (dir_name, name, name[0]+1);
1395 memcpy (path, name, name[0]+1);
1396 p2cstr (path);
1397
1398 cipb.dirInfo.ioDrParID = dir_id;
1399 cipb.dirInfo.ioNamePtr = dir_name;
1400
1401 do
1402 {
1403 cipb.dirInfo.ioVRefNum = vol_ref_num;
1404 cipb.dirInfo.ioFDirIndex = -1;
1405 cipb.dirInfo.ioDrDirID = cipb.dirInfo.ioDrParID;
1406 /* go up to parent each time */
1407
1408 err = PBGetCatInfo (&cipb, false);
1409 if (err != noErr)
1410 return 0;
7d0393cf 1411
1a578e9b
AC
1412 p2cstr (dir_name);
1413 if (strlen (dir_name) + strlen (path) + 1 >= man_path_len)
1414 return 0;
1415
1416 strcat (dir_name, ":");
1417 strcat (dir_name, path);
1418 /* attach to front since we're going up directory tree */
1419 strcpy (path, dir_name);
1420 }
1421 while (cipb.dirInfo.ioDrDirID != fsRtDirID);
1422 /* stop when we see the volume's root directory */
7d0393cf 1423
1a578e9b
AC
1424 return 1; /* success */
1425}
1426
e0f712ba 1427#ifndef MAC_OSX
1a578e9b
AC
1428
1429int
1430readlink (const char *path, char *buf, int bufsiz)
1431{
1432 char mac_sym_link_name[MAXPATHLEN+1];
1433 OSErr err;
1434 FSSpec fsspec;
1435 Boolean target_is_folder, was_aliased;
1436 Str255 directory_name, mac_pathname;
1437 CInfoPBRec cipb;
1438
60fe1161 1439 if (posix_to_mac_pathname (path, mac_sym_link_name, MAXPATHLEN+1) == 0)
1a578e9b
AC
1440 return -1;
1441
1442 c2pstr (mac_sym_link_name);
1443 err = FSMakeFSSpec (0, 0, mac_sym_link_name, &fsspec);
1444 if (err != noErr)
1445 {
1446 errno = ENOENT;
1447 return -1;
1448 }
1449
1450 err = ResolveAliasFile (&fsspec, true, &target_is_folder, &was_aliased);
1451 if (err != noErr || !was_aliased)
1452 {
1453 errno = ENOENT;
1454 return -1;
1455 }
1456
1457 if (path_from_vol_dir_name (mac_pathname, 255, fsspec.vRefNum, fsspec.parID,
1458 fsspec.name) == 0)
1459 {
1460 errno = ENOENT;
1461 return -1;
1462 }
1463
60fe1161 1464 if (mac_to_posix_pathname (mac_pathname, buf, bufsiz) == 0)
1a578e9b
AC
1465 {
1466 errno = ENOENT;
1467 return -1;
1468 }
1469
1470 return strlen (buf);
1471}
1472
1473
1474/* Convert a path to one with aliases fully expanded. */
1475
1476static int
1477find_true_pathname (const char *path, char *buf, int bufsiz)
1478{
1479 char *q, temp[MAXPATHLEN+1];
1480 const char *p;
1481 int len;
1482
1483 if (bufsiz <= 0 || path == 0 || path[0] == '\0')
1484 return -1;
1485
1486 buf[0] = '\0';
7d0393cf 1487
1a578e9b
AC
1488 p = path;
1489 if (*p == '/')
1490 q = strchr (p + 1, '/');
1491 else
1492 q = strchr (p, '/');
1493 len = 0; /* loop may not be entered, e.g., for "/" */
1494
1495 while (q)
1496 {
1497 strcpy (temp, buf);
1498 strncat (temp, p, q - p);
1499 len = readlink (temp, buf, bufsiz);
1500 if (len <= -1)
1501 {
1502 if (strlen (temp) + 1 > bufsiz)
1503 return -1;
1504 strcpy (buf, temp);
1505 }
1506 strcat (buf, "/");
1507 len++;
1508 p = q + 1;
1509 q = strchr(p, '/');
1510 }
7d0393cf 1511
1a578e9b
AC
1512 if (len + strlen (p) + 1 >= bufsiz)
1513 return -1;
7d0393cf 1514
1a578e9b
AC
1515 strcat (buf, p);
1516 return len + strlen (p);
1517}
1518
1519
1520mode_t
1521umask (mode_t numask)
1522{
1523 static mode_t mask = 022;
1524 mode_t oldmask = mask;
1525 mask = numask;
1526 return oldmask;
1527}
1528
1529
1530int
1531chmod (const char *path, mode_t mode)
1532{
1533 /* say it always succeed for now */
1534 return 0;
1535}
1536
1537
1538int
1539dup (int oldd)
1540{
1541#ifdef __MRC__
1542 return fcntl (oldd, F_DUPFD, 0);
1543#elif __MWERKS__
1544 /* current implementation of fcntl in fcntl.mac.c simply returns old
1545 descriptor */
1546 return fcntl (oldd, F_DUPFD);
1547#else
1548You lose!!!
1549#endif
1550}
1551
1552
1553/* This is from the original sysdep.c. Emulate BSD dup2. First close
1554 newd if it already exists. Then, attempt to dup oldd. If not
1555 successful, call dup2 recursively until we are, then close the
1556 unsuccessful ones. */
1557
1558int
1559dup2 (int oldd, int newd)
1560{
1561 int fd, ret;
7d0393cf 1562
1a578e9b
AC
1563 close (newd);
1564
1565 fd = dup (oldd);
1566 if (fd == -1)
1567 return -1;
1568 if (fd == newd)
1569 return newd;
1570 ret = dup2 (oldd, newd);
1571 close (fd);
1572 return ret;
1573}
1574
1575
1576/* let it fail for now */
1577
1578char *
1579sbrk (int incr)
1580{
1581 return (char *) -1;
1582}
1583
1584
1585int
1586fsync (int fd)
1587{
1588 return 0;
1589}
1590
1591
1592int
1593ioctl (int d, int request, void *argp)
1594{
1595 return -1;
1596}
1597
1598
1599#ifdef __MRC__
1600int
1601isatty (int fildes)
1602{
1603 if (fildes >=0 && fildes <= 2)
1604 return 1;
1605 else
1606 return 0;
1607}
1608
1609
1610int
1611getgid ()
1612{
1613 return 100;
1614}
1615
1616
1617int
1618getegid ()
1619{
1620 return 100;
1621}
1622
1623
1624int
1625getuid ()
1626{
1627 return 200;
1628}
1629
1630
1631int
1632geteuid ()
1633{
1634 return 200;
1635}
1636#endif /* __MRC__ */
1637
1638
1639#ifdef __MWERKS__
e0f712ba 1640#if __MSL__ < 0x6000
1a578e9b
AC
1641#undef getpid
1642int
1643getpid ()
1644{
1645 return 9999;
1646}
1647#endif
1648#endif /* __MWERKS__ */
1649
e0f712ba
AC
1650#endif /* ! MAC_OSX */
1651
1a578e9b
AC
1652
1653/* Return the path to the directory in which Emacs can create
1654 temporary files. The MacOS "temporary items" directory cannot be
1655 used because it removes the file written by a process when it
1656 exits. In that sense it's more like "/dev/null" than "/tmp" (but
1657 again not exactly). And of course Emacs needs to read back the
1658 files written by its subprocesses. So here we write the files to a
1659 directory "Emacs" in the Preferences Folder. This directory is
1660 created if it does not exist. */
1661
e0f712ba 1662char *
1a578e9b
AC
1663get_temp_dir_name ()
1664{
1665 static char *temp_dir_name = NULL;
1666 short vol_ref_num;
1667 long dir_id;
1668 OSErr err;
1669 Str255 dir_name, full_path;
1670 CInfoPBRec cpb;
1671 char unix_dir_name[MAXPATHLEN+1];
1672 DIR *dir;
7d0393cf 1673
1a578e9b
AC
1674 /* Cache directory name with pointer temp_dir_name.
1675 Look for it only the first time. */
1676 if (!temp_dir_name)
1677 {
1678 err = FindFolder (kOnSystemDisk, kPreferencesFolderType, kCreateFolder,
1679 &vol_ref_num, &dir_id);
1680 if (err != noErr)
1681 return NULL;
7d0393cf 1682
1a578e9b
AC
1683 if (!path_from_vol_dir_name (full_path, 255, vol_ref_num, dir_id, "\p"))
1684 return NULL;
1685
1686 if (strlen (full_path) + 6 <= MAXPATHLEN)
1687 strcat (full_path, "Emacs:");
7d0393cf 1688 else
1a578e9b
AC
1689 return NULL;
1690
60fe1161 1691 if (!mac_to_posix_pathname (full_path, unix_dir_name, MAXPATHLEN+1))
1a578e9b 1692 return NULL;
7d0393cf 1693
1a578e9b
AC
1694 dir = opendir (unix_dir_name); /* check whether temp directory exists */
1695 if (dir)
1696 closedir (dir);
1697 else if (mkdir (unix_dir_name, 0700) != 0) /* create it if not */
1698 return NULL;
1699
1700 temp_dir_name = (char *) malloc (strlen (unix_dir_name) + 1);
1701 strcpy (temp_dir_name, unix_dir_name);
1702 }
1703
1704 return temp_dir_name;
1705}
1706
e0f712ba 1707#ifndef MAC_OSX
1a578e9b
AC
1708
1709/* Allocate and construct an array of pointers to strings from a list
1710 of strings stored in a 'STR#' resource. The returned pointer array
1711 is stored in the style of argv and environ: if the 'STR#' resource
7d0393cf 1712 contains numString strings, a pointer array with numString+1
1a578e9b
AC
1713 elements is returned in which the last entry contains a null
1714 pointer. The pointer to the pointer array is passed by pointer in
1715 parameter t. The resource ID of the 'STR#' resource is passed in
1716 parameter StringListID.
1717 */
1718
1719void
1720get_string_list (char ***t, short string_list_id)
1721{
1722 Handle h;
1723 Ptr p;
1724 int i, num_strings;
1725
1726 h = GetResource ('STR#', string_list_id);
1727 if (h)
1728 {
1729 HLock (h);
1730 p = *h;
1731 num_strings = * (short *) p;
1732 p += sizeof(short);
1733 *t = (char **) malloc (sizeof (char *) * (num_strings + 1));
1734 for (i = 0; i < num_strings; i++)
1735 {
1736 short length = *p++;
1737 (*t)[i] = (char *) malloc (length + 1);
1738 strncpy ((*t)[i], p, length);
1739 (*t)[i][length] = '\0';
1740 p += length;
1741 }
1742 (*t)[num_strings] = 0;
1743 HUnlock (h);
1744 }
1745 else
1746 {
1747 /* Return no string in case GetResource fails. Bug fixed by
1748 Ikegami Tsutomu. Caused MPW build to crash without sym -on
1749 option (no sym -on implies -opt local). */
1750 *t = (char **) malloc (sizeof (char *));
1751 (*t)[0] = 0;
1752 }
1753}
1754
1755
1756static char *
1757get_path_to_system_folder ()
1758{
1759 short vol_ref_num;
1760 long dir_id;
1761 OSErr err;
1762 Str255 dir_name, full_path;
1763 CInfoPBRec cpb;
1764 static char system_folder_unix_name[MAXPATHLEN+1];
1765 DIR *dir;
7d0393cf 1766
1a578e9b
AC
1767 err = FindFolder (kOnSystemDisk, kSystemFolderType, kDontCreateFolder,
1768 &vol_ref_num, &dir_id);
1769 if (err != noErr)
1770 return NULL;
7d0393cf 1771
1a578e9b
AC
1772 if (!path_from_vol_dir_name (full_path, 255, vol_ref_num, dir_id, "\p"))
1773 return NULL;
1774
e0f712ba
AC
1775 if (!mac_to_posix_pathname (full_path, system_folder_unix_name,
1776 MAXPATHLEN+1))
1a578e9b 1777 return NULL;
7d0393cf 1778
1a578e9b
AC
1779 return system_folder_unix_name;
1780}
1781
1782
1783char **environ;
1784
1785#define ENVIRON_STRING_LIST_ID 128
1786
1787/* Get environment variable definitions from STR# resource. */
1788
1789void
1790init_environ ()
1791{
1792 int i;
7d0393cf 1793
1a578e9b
AC
1794 get_string_list (&environ, ENVIRON_STRING_LIST_ID);
1795
1796 i = 0;
1797 while (environ[i])
1798 i++;
1799
1800 /* Make HOME directory the one Emacs starts up in if not specified
1801 by resource. */
1802 if (getenv ("HOME") == NULL)
1803 {
1804 environ = (char **) realloc (environ, sizeof (char *) * (i + 2));
1805 if (environ)
1806 {
1807 environ[i] = (char *) malloc (strlen (my_passwd_dir) + 6);
1808 if (environ[i])
1809 {
1810 strcpy (environ[i], "HOME=");
1811 strcat (environ[i], my_passwd_dir);
1812 }
1813 environ[i+1] = 0;
1814 i++;
1815 }
1816 }
1817
1818 /* Make HOME directory the one Emacs starts up in if not specified
1819 by resource. */
1820 if (getenv ("MAIL") == NULL)
1821 {
1822 environ = (char **) realloc (environ, sizeof (char *) * (i + 2));
1823 if (environ)
1824 {
1825 char * path_to_system_folder = get_path_to_system_folder ();
1826 environ[i] = (char *) malloc (strlen (path_to_system_folder) + 22);
1827 if (environ[i])
1828 {
1829 strcpy (environ[i], "MAIL=");
1830 strcat (environ[i], path_to_system_folder);
1831 strcat (environ[i], "Eudora Folder/In");
1832 }
1833 environ[i+1] = 0;
1834 }
1835 }
1836}
1837
1838
1839/* Return the value of the environment variable NAME. */
1840
1841char *
1842getenv (const char *name)
1843{
1844 int length = strlen(name);
1845 char **e;
1846
1847 for (e = environ; *e != 0; e++)
1848 if (strncmp(*e, name, length) == 0 && (*e)[length] == '=')
1849 return &(*e)[length + 1];
1850
1851 if (strcmp (name, "TMPDIR") == 0)
1852 return get_temp_dir_name ();
1853
1854 return 0;
1855}
1856
1857
1858#ifdef __MRC__
1859/* see Interfaces&Libraries:Interfaces:CIncludes:signal.h */
1860char *sys_siglist[] =
1861{
1862 "Zero is not a signal!!!",
1863 "Abort", /* 1 */
1864 "Interactive user interrupt", /* 2 */ "?",
1865 "Floating point exception", /* 4 */ "?", "?", "?",
1866 "Illegal instruction", /* 8 */ "?", "?", "?", "?", "?", "?", "?",
1867 "Segment violation", /* 16 */ "?", "?", "?", "?", "?", "?", "?",
1868 "?", "?", "?", "?", "?", "?", "?", "?",
1869 "Terminal" /* 32 */
1870};
1871#elif __MWERKS__
1872char *sys_siglist[] =
1873{
1874 "Zero is not a signal!!!",
1875 "Abort",
1876 "Floating point exception",
1877 "Illegal instruction",
1878 "Interactive user interrupt",
1879 "Segment violation",
1880 "Terminal"
1881};
e0f712ba 1882#else /* not __MRC__ and not __MWERKS__ */
1a578e9b 1883You lose!!!
e0f712ba 1884#endif /* not __MRC__ and not __MWERKS__ */
1a578e9b
AC
1885
1886
1887#include <utsname.h>
1888
1889int
1890uname (struct utsname *name)
1891{
1892 char **system_name;
1893 system_name = GetString (-16413); /* IM - Resource Manager Reference */
1894 if (system_name)
1895 {
1896 BlockMove (*system_name, name->nodename, (*system_name)[0]+1);
1897 p2cstr (name->nodename);
1898 return 0;
1899 }
1900 else
1901 return -1;
1902}
1903
1904
1905#include <Processes.h>
1906#include <EPPC.h>
1907
1908/* Event class of HLE sent to subprocess. */
1909const OSType kEmacsSubprocessSend = 'ESND';
1910
1911/* Event class of HLE sent back from subprocess. */
1912const OSType kEmacsSubprocessReply = 'ERPY';
1913
1914
1915char *
1916mystrchr (char *s, char c)
1917{
1918 while (*s && *s != c)
1919 {
1920 if (*s == '\\')
1921 s++;
1922 s++;
1923 }
1924
1925 if (*s)
1926 {
1927 *s = '\0';
1928 return s;
1929 }
1930 else
1931 return NULL;
1932}
1933
1934
1935char *
1936mystrtok (char *s)
7d0393cf 1937{
1a578e9b
AC
1938 while (*s)
1939 s++;
1940
1941 return s + 1;
1942}
1943
1944
1945void
1946mystrcpy (char *to, char *from)
1947{
1948 while (*from)
1949 {
1950 if (*from == '\\')
1951 from++;
1952 *to++ = *from++;
1953 }
1954 *to = '\0';
1955}
1956
1957
1958/* Start a Mac subprocess. Arguments for it is passed in argv (null
1959 terminated). The process should run with the default directory
1960 "workdir", read input from "infn", and write output and error to
1961 "outfn" and "errfn", resp. The Process Manager call
1962 LaunchApplication is used to start the subprocess. We use high
1963 level events as the mechanism to pass arguments to the subprocess
1964 and to make Emacs wait for the subprocess to terminate and pass
1965 back a result code. The bulk of the code here packs the arguments
1966 into one message to be passed together with the high level event.
1967 Emacs also sometimes starts a subprocess using a shell to perform
1968 wildcard filename expansion. Since we don't really have a shell on
1969 the Mac, this case is detected and the starting of the shell is
1970 by-passed. We really need to add code here to do filename
1971 expansion to support such functionality. */
1972
1973int
1974run_mac_command (argv, workdir, infn, outfn, errfn)
1975 unsigned char **argv;
1976 const char *workdir;
1977 const char *infn, *outfn, *errfn;
1978{
e0f712ba
AC
1979#ifdef TARGET_API_MAC_CARBON
1980 return -1;
1981#else /* not TARGET_API_MAC_CARBON */
1a578e9b
AC
1982 char macappname[MAXPATHLEN+1], macworkdir[MAXPATHLEN+1];
1983 char macinfn[MAXPATHLEN+1], macoutfn[MAXPATHLEN+1], macerrfn[MAXPATHLEN+1];
1984 int paramlen, argc, newargc, j, retries;
1985 char **newargv, *param, *p;
1986 OSErr iErr;
1987 FSSpec spec;
1988 LaunchParamBlockRec lpbr;
1989 EventRecord send_event, reply_event;
1990 RgnHandle cursor_region_handle;
1991 TargetID targ;
1992 unsigned long ref_con, len;
7d0393cf 1993
60fe1161 1994 if (posix_to_mac_pathname (workdir, macworkdir, MAXPATHLEN+1) == 0)
1a578e9b 1995 return -1;
60fe1161 1996 if (posix_to_mac_pathname (infn, macinfn, MAXPATHLEN+1) == 0)
1a578e9b 1997 return -1;
60fe1161 1998 if (posix_to_mac_pathname (outfn, macoutfn, MAXPATHLEN+1) == 0)
1a578e9b 1999 return -1;
60fe1161 2000 if (posix_to_mac_pathname (errfn, macerrfn, MAXPATHLEN+1) == 0)
1a578e9b 2001 return -1;
7d0393cf 2002
1a578e9b
AC
2003 paramlen = strlen (macworkdir) + strlen (macinfn) + strlen (macoutfn)
2004 + strlen (macerrfn) + 4; /* count nulls at end of strings */
2005
2006 argc = 0;
2007 while (argv[argc])
2008 argc++;
2009
2010 if (argc == 0)
2011 return -1;
2012
2013 /* If a subprocess is invoked with a shell, we receive 3 arguments
2014 of the form: "<path to emacs bins>/sh" "-c" "<path to emacs
2015 bins>/<command> <command args>" */
2016 j = strlen (argv[0]);
2017 if (j >= 3 && strcmp (argv[0]+j-3, "/sh") == 0
2018 && argc == 3 && strcmp (argv[1], "-c") == 0)
2019 {
2020 char *command, *t, tempmacpathname[MAXPATHLEN+1];
7d0393cf 2021
1a578e9b
AC
2022 /* The arguments for the command in argv[2] are separated by
2023 spaces. Count them and put the count in newargc. */
2024 command = (char *) alloca (strlen (argv[2])+2);
2025 strcpy (command, argv[2]);
2026 if (command[strlen (command) - 1] != ' ')
2027 strcat (command, " ");
7d0393cf 2028
1a578e9b
AC
2029 t = command;
2030 newargc = 0;
2031 t = mystrchr (t, ' ');
2032 while (t)
2033 {
2034 newargc++;
2035 t = mystrchr (t+1, ' ');
2036 }
7d0393cf 2037
1a578e9b 2038 newargv = (char **) alloca (sizeof (char *) * newargc);
7d0393cf 2039
1a578e9b
AC
2040 t = command;
2041 for (j = 0; j < newargc; j++)
2042 {
2043 newargv[j] = (char *) alloca (strlen (t) + 1);
2044 mystrcpy (newargv[j], t);
2045
2046 t = mystrtok (t);
2047 paramlen += strlen (newargv[j]) + 1;
2048 }
7d0393cf 2049
1a578e9b
AC
2050 if (strncmp (newargv[0], "~emacs/", 7) == 0)
2051 {
60fe1161 2052 if (posix_to_mac_pathname (newargv[0], tempmacpathname, MAXPATHLEN+1)
1a578e9b
AC
2053 == 0)
2054 return -1;
2055 }
2056 else
2057 { /* sometimes Emacs call "sh" without a path for the command */
2058#if 0
2059 char *t = (char *) alloca (strlen (newargv[0]) + 7 + 1);
2060 strcpy (t, "~emacs/");
2061 strcat (t, newargv[0]);
e0f712ba 2062#endif /* 0 */
1a578e9b 2063 Lisp_Object path;
e0f712ba 2064 openp (Vexec_path, build_string (newargv[0]), EXEC_SUFFIXES, &path,
141f653a 2065 make_number (X_OK));
1a578e9b
AC
2066
2067 if (NILP (path))
2068 return -1;
d5db4077 2069 if (posix_to_mac_pathname (SDATA (path), tempmacpathname,
1a578e9b
AC
2070 MAXPATHLEN+1) == 0)
2071 return -1;
2072 }
2073 strcpy (macappname, tempmacpathname);
2074 }
2075 else
7d0393cf 2076 {
60fe1161 2077 if (posix_to_mac_pathname (argv[0], macappname, MAXPATHLEN+1) == 0)
1a578e9b
AC
2078 return -1;
2079
2080 newargv = (char **) alloca (sizeof (char *) * argc);
7d0393cf 2081 newargc = argc;
1a578e9b
AC
2082 for (j = 1; j < argc; j++)
2083 {
2084 if (strncmp (argv[j], "~emacs/", 7) == 0)
2085 {
2086 char *t = strchr (argv[j], ' ');
2087 if (t)
2088 {
2089 char tempcmdname[MAXPATHLEN+1], tempmaccmdname[MAXPATHLEN+1];
2090 strncpy (tempcmdname, argv[j], t-argv[j]);
2091 tempcmdname[t-argv[j]] = '\0';
60fe1161 2092 if (posix_to_mac_pathname (tempcmdname, tempmaccmdname,
1a578e9b
AC
2093 MAXPATHLEN+1) == 0)
2094 return -1;
2095 newargv[j] = (char *) alloca (strlen (tempmaccmdname)
2096 + strlen (t) + 1);
2097 strcpy (newargv[j], tempmaccmdname);
2098 strcat (newargv[j], t);
2099 }
2100 else
2101 {
2102 char tempmaccmdname[MAXPATHLEN+1];
60fe1161 2103 if (posix_to_mac_pathname (argv[j], tempmaccmdname,
1a578e9b
AC
2104 MAXPATHLEN+1) == 0)
2105 return -1;
2106 newargv[j] = (char *) alloca (strlen (tempmaccmdname)+1);
2107 strcpy (newargv[j], tempmaccmdname);
2108 }
2109 }
2110 else
7d0393cf 2111 newargv[j] = argv[j];
1a578e9b
AC
2112 paramlen += strlen (newargv[j]) + 1;
2113 }
2114 }
2115
2116 /* After expanding all the arguments, we now know the length of the
2117 parameter block to be sent to the subprocess as a message
2118 attached to the HLE. */
2119 param = (char *) malloc (paramlen + 1);
2120 if (!param)
2121 return -1;
2122
2123 p = param;
2124 *p++ = newargc;
2125 /* first byte of message contains number of arguments for command */
2126 strcpy (p, macworkdir);
2127 p += strlen (macworkdir);
2128 *p++ = '\0';
2129 /* null terminate strings sent so it's possible to use strcpy over there */
2130 strcpy (p, macinfn);
2131 p += strlen (macinfn);
7d0393cf 2132 *p++ = '\0';
1a578e9b
AC
2133 strcpy (p, macoutfn);
2134 p += strlen (macoutfn);
7d0393cf 2135 *p++ = '\0';
1a578e9b
AC
2136 strcpy (p, macerrfn);
2137 p += strlen (macerrfn);
7d0393cf 2138 *p++ = '\0';
1a578e9b
AC
2139 for (j = 1; j < newargc; j++)
2140 {
2141 strcpy (p, newargv[j]);
2142 p += strlen (newargv[j]);
7d0393cf 2143 *p++ = '\0';
1a578e9b 2144 }
7d0393cf 2145
1a578e9b 2146 c2pstr (macappname);
7d0393cf 2147
1a578e9b 2148 iErr = FSMakeFSSpec (0, 0, macappname, &spec);
7d0393cf 2149
1a578e9b
AC
2150 if (iErr != noErr)
2151 {
2152 free (param);
2153 return -1;
2154 }
2155
2156 lpbr.launchBlockID = extendedBlock;
2157 lpbr.launchEPBLength = extendedBlockLen;
2158 lpbr.launchControlFlags = launchContinue + launchNoFileFlags;
2159 lpbr.launchAppSpec = &spec;
2160 lpbr.launchAppParameters = NULL;
2161
2162 iErr = LaunchApplication (&lpbr); /* call the subprocess */
2163 if (iErr != noErr)
2164 {
2165 free (param);
2166 return -1;
2167 }
2168
2169 send_event.what = kHighLevelEvent;
2170 send_event.message = kEmacsSubprocessSend;
2171 /* Event ID stored in "where" unused */
2172
2173 retries = 3;
2174 /* OS may think current subprocess has terminated if previous one
2175 terminated recently. */
2176 do
2177 {
2178 iErr = PostHighLevelEvent (&send_event, &lpbr.launchProcessSN, 0, param,
2179 paramlen + 1, receiverIDisPSN);
2180 }
2181 while (iErr == sessClosedErr && retries-- > 0);
2182
2183 if (iErr != noErr)
2184 {
2185 free (param);
2186 return -1;
2187 }
2188
2189 cursor_region_handle = NewRgn ();
7d0393cf 2190
1a578e9b
AC
2191 /* Wait for the subprocess to finish, when it will send us a ERPY
2192 high level event. */
2193 while (1)
2194 if (WaitNextEvent (highLevelEventMask, &reply_event, 180,
2195 cursor_region_handle)
2196 && reply_event.message == kEmacsSubprocessReply)
2197 break;
7d0393cf 2198
1a578e9b
AC
2199 /* The return code is sent through the refCon */
2200 iErr = AcceptHighLevelEvent (&targ, &ref_con, NULL, &len);
2201 if (iErr != noErr)
2202 {
2203 DisposeHandle ((Handle) cursor_region_handle);
2204 free (param);
2205 return -1;
2206 }
7d0393cf 2207
1a578e9b
AC
2208 DisposeHandle ((Handle) cursor_region_handle);
2209 free (param);
2210
2211 return ref_con;
e0f712ba 2212#endif /* not TARGET_API_MAC_CARBON */
1a578e9b
AC
2213}
2214
2215
2216DIR *
2217opendir (const char *dirname)
2218{
7d0393cf 2219 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
1a578e9b
AC
2220 char mac_pathname[MAXPATHLEN+1], vol_name[MAXPATHLEN+1];
2221 DIR *dirp;
2222 CInfoPBRec cipb;
2223 HVolumeParam vpb;
2224 int len, vol_name_len;
7d0393cf 2225
1a578e9b
AC
2226 if (find_true_pathname (dirname, true_pathname, MAXPATHLEN+1) == -1)
2227 return 0;
7d0393cf 2228
1a578e9b
AC
2229 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
2230 if (len > -1)
2231 fully_resolved_name[len] = '\0';
2232 else
2233 strcpy (fully_resolved_name, true_pathname);
2234
2235 dirp = (DIR *) malloc (sizeof(DIR));
2236 if (!dirp)
2237 return 0;
2238
2239 /* Handle special case when dirname is "/": sets up for readir to
2240 get all mount volumes. */
2241 if (strcmp (fully_resolved_name, "/") == 0)
2242 {
2243 dirp->getting_volumes = 1; /* special all mounted volumes DIR struct */
2244 dirp->current_index = 1; /* index for first volume */
2245 return dirp;
2246 }
2247
2248 /* Handle typical cases: not accessing all mounted volumes. */
60fe1161 2249 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
1a578e9b
AC
2250 return 0;
2251
2252 /* Emacs calls opendir without the trailing '/', Mac needs trailing ':' */
2253 len = strlen (mac_pathname);
2254 if (mac_pathname[len - 1] != ':' && len < MAXPATHLEN)
2255 strcat (mac_pathname, ":");
7d0393cf 2256
1a578e9b
AC
2257 /* Extract volume name */
2258 vol_name_len = strchr (mac_pathname, ':') - mac_pathname;
2259 strncpy (vol_name, mac_pathname, vol_name_len);
2260 vol_name[vol_name_len] = '\0';
2261 strcat (vol_name, ":");
2262
2263 c2pstr (mac_pathname);
2264 cipb.hFileInfo.ioNamePtr = mac_pathname;
2265 /* using full pathname so vRefNum and DirID ignored */
2266 cipb.hFileInfo.ioVRefNum = 0;
2267 cipb.hFileInfo.ioDirID = 0;
2268 cipb.hFileInfo.ioFDirIndex = 0;
2269 /* set to 0 to get information about specific dir or file */
7d0393cf 2270
1a578e9b
AC
2271 errno = PBGetCatInfo (&cipb, false);
2272 if (errno != noErr)
2273 {
2274 errno = ENOENT;
2275 return 0;
2276 }
2277
2278 if (!(cipb.hFileInfo.ioFlAttrib & 0x10)) /* bit 4 = 1 for directories */
2279 return 0; /* not a directory */
2280
2281 dirp->dir_id = cipb.dirInfo.ioDrDirID; /* used later in readdir */
2282 dirp->getting_volumes = 0;
2283 dirp->current_index = 1; /* index for first file/directory */
2284
2285 c2pstr (vol_name);
2286 vpb.ioNamePtr = vol_name;
2287 /* using full pathname so vRefNum and DirID ignored */
2288 vpb.ioVRefNum = 0;
2289 vpb.ioVolIndex = -1;
2290 errno = PBHGetVInfo ((union HParamBlockRec *) &vpb, false);
2291 if (errno != noErr)
2292 {
2293 errno = ENOENT;
2294 return 0;
2295 }
2296
2297 dirp->vol_ref_num = vpb.ioVRefNum;
7d0393cf 2298
1a578e9b
AC
2299 return dirp;
2300}
2301
2302int
2303closedir (DIR *dp)
2304{
2305 free (dp);
2306
2307 return 0;
2308}
2309
2310
2311struct dirent *
2312readdir (DIR *dp)
2313{
2314 HParamBlockRec hpblock;
2315 CInfoPBRec cipb;
2316 static struct dirent s_dirent;
2317 static Str255 s_name;
2318 int done;
2319 char *p;
2320
2321 /* Handle the root directory containing the mounted volumes. Call
2322 PBHGetVInfo specifying an index to obtain the info for a volume.
2323 PBHGetVInfo returns an error when it receives an index beyond the
2324 last volume, at which time we should return a nil dirent struct
2325 pointer. */
2326 if (dp->getting_volumes)
2327 {
2328 hpblock.volumeParam.ioNamePtr = s_name;
2329 hpblock.volumeParam.ioVRefNum = 0;
2330 hpblock.volumeParam.ioVolIndex = dp->current_index;
7d0393cf 2331
1a578e9b
AC
2332 errno = PBHGetVInfo (&hpblock, false);
2333 if (errno != noErr)
2334 {
2335 errno = ENOENT;
2336 return 0;
2337 }
7d0393cf 2338
1a578e9b
AC
2339 p2cstr (s_name);
2340 strcat (s_name, "/"); /* need "/" for stat to work correctly */
2341
2342 dp->current_index++;
2343
2344 s_dirent.d_ino = hpblock.volumeParam.ioVRefNum;
2345 s_dirent.d_name = s_name;
7d0393cf 2346
1a578e9b
AC
2347 return &s_dirent;
2348 }
2349 else
2350 {
2351 cipb.hFileInfo.ioVRefNum = dp->vol_ref_num;
2352 cipb.hFileInfo.ioNamePtr = s_name;
2353 /* location to receive filename returned */
2354
2355 /* return only visible files */
2356 done = false;
2357 while (!done)
2358 {
2359 cipb.hFileInfo.ioDirID = dp->dir_id;
2360 /* directory ID found by opendir */
2361 cipb.hFileInfo.ioFDirIndex = dp->current_index;
7d0393cf 2362
1a578e9b
AC
2363 errno = PBGetCatInfo (&cipb, false);
2364 if (errno != noErr)
2365 {
2366 errno = ENOENT;
2367 return 0;
2368 }
7d0393cf
JB
2369
2370 /* insist on a visible entry */
1a578e9b
AC
2371 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* directory? */
2372 done = !(cipb.dirInfo.ioDrUsrWds.frFlags & fInvisible);
2373 else
2374 done = !(cipb.hFileInfo.ioFlFndrInfo.fdFlags & fInvisible);
7d0393cf 2375
1a578e9b
AC
2376 dp->current_index++;
2377 }
2378
2379 p2cstr (s_name);
7d0393cf 2380
1a578e9b
AC
2381 p = s_name;
2382 while (*p)
2383 {
2384 if (*p == '/')
2385 *p = ':';
2386 p++;
2387 }
2388
2389 s_dirent.d_ino = cipb.dirInfo.ioDrDirID;
2390 /* value unimportant: non-zero for valid file */
2391 s_dirent.d_name = s_name;
7d0393cf 2392
1a578e9b
AC
2393 return &s_dirent;
2394 }
2395}
2396
2397
2398char *
2399getwd (char *path)
2400{
2401 char mac_pathname[MAXPATHLEN+1];
2402 Str255 directory_name;
2403 OSErr errno;
2404 CInfoPBRec cipb;
2405
2406 if (path_from_vol_dir_name (mac_pathname, 255, 0, 0, "\p") == 0)
2407 return NULL;
2408
60fe1161 2409 if (mac_to_posix_pathname (mac_pathname, path, MAXPATHLEN+1) == 0)
1a578e9b
AC
2410 return 0;
2411 else
2412 return path;
2413}
2414
e0f712ba
AC
2415#endif /* ! MAC_OSX */
2416
1a578e9b
AC
2417
2418void
2419initialize_applescript ()
2420{
2421 AEDesc null_desc;
2422 OSAError osaerror;
7d0393cf 2423
1a578e9b
AC
2424 /* if open fails, as_scripting_component is set to NULL. Its
2425 subsequent use in OSA calls will fail with badComponentInstance
2426 error. */
2427 as_scripting_component = OpenDefaultComponent (kOSAComponentType,
2428 kAppleScriptSubtype);
2429
2430 null_desc.descriptorType = typeNull;
2431 null_desc.dataHandle = 0;
2432 osaerror = OSAMakeContext (as_scripting_component, &null_desc,
2433 kOSANullScript, &as_script_context);
2434 if (osaerror)
2435 as_script_context = kOSANullScript;
2436 /* use default context if create fails */
2437}
2438
2439
2440void terminate_applescript()
2441{
2442 OSADispose (as_scripting_component, as_script_context);
2443 CloseComponent (as_scripting_component);
2444}
2445
2446
2447/* Compile and execute the AppleScript SCRIPT and return the error
2448 status as function value. A zero is returned if compilation and
2449 execution is successful, in which case RESULT returns a pointer to
2450 a string containing the resulting script value. Otherwise, the Mac
2451 error code is returned and RESULT returns a pointer to an error
2452 string. In both cases the caller should deallocate the storage
2453 used by the string pointed to by RESULT if it is non-NULL. For
2454 documentation on the MacOS scripting architecture, see Inside
2455 Macintosh - Interapplication Communications: Scripting Components. */
2456
2457static long
2458do_applescript (char *script, char **result)
2459{
2460 AEDesc script_desc, result_desc, error_desc;
2461 OSErr error;
2462 OSAError osaerror;
2463 long length;
2464
2465 *result = 0;
2466
84c0c2cc
AC
2467 if (!as_scripting_component)
2468 initialize_applescript();
2469
1a578e9b
AC
2470 error = AECreateDesc (typeChar, script, strlen(script), &script_desc);
2471 if (error)
2472 return error;
2473
2474 osaerror = OSADoScript (as_scripting_component, &script_desc, kOSANullScript,
2475 typeChar, kOSAModeNull, &result_desc);
2476
2477 if (osaerror == errOSAScriptError)
2478 {
2479 /* error executing AppleScript: retrieve error message */
2480 if (!OSAScriptError (as_scripting_component, kOSAErrorMessage, typeChar,
2481 &error_desc))
2482 {
e0f712ba
AC
2483#if TARGET_API_MAC_CARBON
2484 length = AEGetDescDataSize (&error_desc);
2485 *result = (char *) xmalloc (length + 1);
2486 if (*result)
2487 {
2488 AEGetDescData (&error_desc, *result, length);
2489 *(*result + length) = '\0';
2490 }
2491#else /* not TARGET_API_MAC_CARBON */
1a578e9b
AC
2492 HLock (error_desc.dataHandle);
2493 length = GetHandleSize(error_desc.dataHandle);
2494 *result = (char *) xmalloc (length + 1);
2495 if (*result)
2496 {
2497 memcpy (*result, *(error_desc.dataHandle), length);
2498 *(*result + length) = '\0';
2499 }
2500 HUnlock (error_desc.dataHandle);
e0f712ba 2501#endif /* not TARGET_API_MAC_CARBON */
1a578e9b
AC
2502 AEDisposeDesc (&error_desc);
2503 }
2504 }
2505 else if (osaerror == noErr) /* success: retrieve resulting script value */
2506 {
e0f712ba
AC
2507#if TARGET_API_MAC_CARBON
2508 length = AEGetDescDataSize (&result_desc);
2509 *result = (char *) xmalloc (length + 1);
2510 if (*result)
2511 {
2512 AEGetDescData (&result_desc, *result, length);
2513 *(*result + length) = '\0';
2514 }
2515#else /* not TARGET_API_MAC_CARBON */
1a578e9b
AC
2516 HLock (result_desc.dataHandle);
2517 length = GetHandleSize(result_desc.dataHandle);
2518 *result = (char *) xmalloc (length + 1);
2519 if (*result)
2520 {
2521 memcpy (*result, *(result_desc.dataHandle), length);
2522 *(*result + length) = '\0';
2523 }
2524 HUnlock (result_desc.dataHandle);
e0f712ba 2525#endif /* not TARGET_API_MAC_CARBON */
84c0c2cc 2526 AEDisposeDesc (&result_desc);
1a578e9b
AC
2527 }
2528
2529 AEDisposeDesc (&script_desc);
1a578e9b
AC
2530
2531 return osaerror;
2532}
2533
2534
2535DEFUN ("do-applescript", Fdo_applescript, Sdo_applescript, 1, 1, 0,
e0f712ba
AC
2536 doc: /* Compile and execute AppleScript SCRIPT and retrieve and return the result.
2537If compilation and execution are successful, the resulting script
2538value is returned as a string. Otherwise the function aborts and
2539displays the error message returned by the AppleScript scripting
2540component. */)
1a578e9b
AC
2541 (script)
2542 Lisp_Object script;
2543{
2544 char *result, *temp;
2545 Lisp_Object lisp_result;
2546 long status;
2547
e0f712ba 2548 CHECK_STRING (script);
7d0393cf 2549
d5db4077 2550 status = do_applescript (SDATA (script), &result);
1a578e9b
AC
2551 if (status)
2552 {
2553 if (!result)
84c0c2cc 2554 error ("AppleScript error %d", status);
1a578e9b
AC
2555 else
2556 {
2557 /* Unfortunately only OSADoScript in do_applescript knows how
2558 how large the resulting script value or error message is
2559 going to be and therefore as caller memory must be
2560 deallocated here. It is necessary to free the error
2561 message before calling error to avoid a memory leak. */
2562 temp = (char *) alloca (strlen (result) + 1);
2563 strcpy (temp, result);
2564 xfree (result);
2565 error (temp);
2566 }
2567 }
2568 else
2569 {
2570 lisp_result = build_string (result);
2571 xfree (result);
2572 return lisp_result;
2573 }
2574}
2575
2576
e0f712ba
AC
2577DEFUN ("mac-file-name-to-posix", Fmac_file_name_to_posix,
2578 Smac_file_name_to_posix, 1, 1, 0,
2579 doc: /* Convert Macintosh filename to Posix form. */)
2580 (mac_filename)
2581 Lisp_Object mac_filename;
1a578e9b 2582{
60fe1161 2583 char posix_filename[MAXPATHLEN+1];
1a578e9b 2584
e0f712ba 2585 CHECK_STRING (mac_filename);
7d0393cf 2586
d5db4077 2587 if (mac_to_posix_pathname (SDATA (mac_filename), posix_filename,
1a578e9b 2588 MAXPATHLEN))
60fe1161 2589 return build_string (posix_filename);
1a578e9b
AC
2590 else
2591 return Qnil;
2592}
2593
2594
e0f712ba
AC
2595DEFUN ("posix-file-name-to-mac", Fposix_file_name_to_mac,
2596 Sposix_file_name_to_mac, 1, 1, 0,
2597 doc: /* Convert Posix filename to Mac form. */)
2598 (posix_filename)
2599 Lisp_Object posix_filename;
1a578e9b
AC
2600{
2601 char mac_filename[MAXPATHLEN+1];
2602
e0f712ba 2603 CHECK_STRING (posix_filename);
7d0393cf 2604
d5db4077 2605 if (posix_to_mac_pathname (SDATA (posix_filename), mac_filename,
1a578e9b
AC
2606 MAXPATHLEN))
2607 return build_string (mac_filename);
2608 else
2609 return Qnil;
2610}
2611
2612
2613/* set interprogram-paste-function to mac-paste-function in mac-win.el
2614 to enable Emacs to obtain the contents of the Mac clipboard. */
2615DEFUN ("mac-paste-function", Fmac_paste_function, Smac_paste_function, 0, 0, 0,
e0f712ba
AC
2616 doc: /* Return the contents of the Mac clipboard as a string. */)
2617 ()
1a578e9b 2618{
e0f712ba
AC
2619#if TARGET_API_MAC_CARBON
2620 ScrapRef scrap;
2621 ScrapFlavorFlags sff;
2622 Size s;
2623 int i;
2624 char *data;
2625
2626 if (GetCurrentScrap (&scrap) != noErr)
2627 return Qnil;
2628
2629 if (GetScrapFlavorFlags (scrap, kScrapFlavorTypeText, &sff) != noErr)
2630 return Qnil;
2631
2632 if (GetScrapFlavorSize (scrap, kScrapFlavorTypeText, &s) != noErr)
2633 return Qnil;
2634
2635 if ((data = (char*) alloca (s)) == NULL)
2636 return Qnil;
2637
2638 if (GetScrapFlavorData (scrap, kScrapFlavorTypeText, &s, data) != noErr
2639 || s == 0)
2640 return Qnil;
7d0393cf 2641
e0f712ba
AC
2642 /* Emacs expects clipboard contents have Unix-style eol's */
2643 for (i = 0; i < s; i++)
2644 if (data[i] == '\r')
2645 data[i] = '\n';
2646
2647 return make_string (data, s);
2648#else /* not TARGET_API_MAC_CARBON */
1a578e9b
AC
2649 Lisp_Object value;
2650 Handle my_handle;
2651 long scrap_offset, rc, i;
2652
2653 my_handle = NewHandle (0); /* allocate 0-length data area */
2654
2655 rc = GetScrap (my_handle, 'TEXT', &scrap_offset);
2656 if (rc < 0)
2657 return Qnil;
2658
2659 HLock (my_handle);
2660
2661 /* Emacs expects clipboard contents have Unix-style eol's */
2662 for (i = 0; i < rc; i++)
2663 if ((*my_handle)[i] == '\r')
2664 (*my_handle)[i] = '\n';
2665
2666 value = make_string (*my_handle, rc);
2667
2668 HUnlock (my_handle);
7d0393cf 2669
1a578e9b
AC
2670 DisposeHandle (my_handle);
2671
2672 return value;
e0f712ba 2673#endif /* not TARGET_API_MAC_CARBON */
1a578e9b
AC
2674}
2675
2676
2677/* set interprogram-cut-function to mac-cut-function in mac-win.el
2678 to enable Emacs to write the top of the kill-ring to the Mac clipboard. */
2679DEFUN ("mac-cut-function", Fmac_cut_function, Smac_cut_function, 1, 2, 0,
e0f712ba 2680 doc: /* Put the value of the string parameter to the Mac clipboard. */)
1a578e9b
AC
2681 (value, push)
2682 Lisp_Object value, push;
2683{
2684 char *buf;
2685 int len, i;
2686
2687 /* fixme: ignore the push flag for now */
2688
e0f712ba 2689 CHECK_STRING (value);
7d0393cf 2690
d5db4077 2691 len = SCHARS (value);
e0f712ba 2692 buf = (char *) alloca (len+1);
d5db4077 2693 bcopy (SDATA (value), buf, len);
e0f712ba 2694 buf[len] = '\0';
7d0393cf 2695
1a578e9b
AC
2696 /* convert to Mac-style eol's before sending to clipboard */
2697 for (i = 0; i < len; i++)
2698 if (buf[i] == '\n')
2699 buf[i] = '\r';
2700
e0f712ba
AC
2701#if TARGET_API_MAC_CARBON
2702 {
2703 ScrapRef scrap;
2704 ClearCurrentScrap ();
2705 if (GetCurrentScrap (&scrap) != noErr)
2706 error ("cannot get current scrap");
2707
2708 if (PutScrapFlavor (scrap, kScrapFlavorTypeText, kScrapFlavorMaskNone, len,
2709 buf) != noErr)
2710 error ("cannot put to scrap");
2711 }
2712#else /* not TARGET_API_MAC_CARBON */
1a578e9b
AC
2713 ZeroScrap ();
2714 PutScrap (len, 'TEXT', buf);
e0f712ba 2715#endif /* not TARGET_API_MAC_CARBON */
7d0393cf 2716
1a578e9b
AC
2717 return Qnil;
2718}
2719
2720
2721DEFUN ("x-selection-exists-p", Fx_selection_exists_p, Sx_selection_exists_p,
e0f712ba
AC
2722 0, 1, 0,
2723 doc: /* Whether there is an owner for the given X Selection.
2724The arg should be the name of the selection in question, typically one of
2725the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.
14bda6db 2726\(Those are literal upper-case symbol names, since that's what X expects.)
e0f712ba
AC
2727For convenience, the symbol nil is the same as `PRIMARY',
2728and t is the same as `SECONDARY'. */)
1a578e9b
AC
2729 (selection)
2730 Lisp_Object selection;
2731{
e0f712ba 2732 CHECK_SYMBOL (selection);
1a578e9b
AC
2733
2734 /* Return nil for PRIMARY and SECONDARY selections; for CLIPBOARD, check
2735 if the clipboard currently has valid text format contents. */
2736
2737 if (EQ (selection, QCLIPBOARD))
2738 {
2739 Lisp_Object val = Qnil;
e0f712ba
AC
2740
2741#if TARGET_API_MAC_CARBON
2742 ScrapRef scrap;
2743 ScrapFlavorFlags sff;
2744
2745 if (GetCurrentScrap (&scrap) == noErr)
2746 if (GetScrapFlavorFlags (scrap, kScrapFlavorTypeText, &sff) == noErr)
2747 val = Qt;
2748#else /* not TARGET_API_MAC_CARBON */
1a578e9b
AC
2749 Handle my_handle;
2750 long rc, scrap_offset;
2751
2752 my_handle = NewHandle (0);
2753
2754 rc = GetScrap (my_handle, 'TEXT', &scrap_offset);
2755 if (rc >= 0)
2756 val = Qt;
2757
2758 DisposeHandle (my_handle);
e0f712ba 2759#endif /* not TARGET_API_MAC_CARBON */
1a578e9b
AC
2760
2761 return val;
2762 }
2763 return Qnil;
2764}
2765
8030369c
AC
2766#ifdef MAC_OSX
2767#undef select
2768
2769extern int inhibit_window_system;
2b187eac 2770extern int noninteractive;
8030369c 2771
bfcf6608
ST
2772#include "blockinput.h"
2773
8030369c
AC
2774/* When Emacs is started from the Finder, SELECT always immediately
2775 returns as if input is present when file descriptor 0 is polled for
2776 input. Strangely, when Emacs is run as a GUI application from the
2777 command line, it blocks in the same situation. This `wrapper' of
2778 the system call SELECT corrects this discrepancy. */
2779int
2780sys_select (n, rfds, wfds, efds, timeout)
bfcf6608
ST
2781 int n;
2782 SELECT_TYPE *rfds;
2783 SELECT_TYPE *wfds;
2784 SELECT_TYPE *efds;
2785 struct timeval *timeout;
8030369c 2786{
bfcf6608
ST
2787 OSErr err;
2788 EMACS_TIME end_time, now, remaining_time;
2789
e082ac9d
ST
2790 if (inhibit_window_system || noninteractive
2791 || rfds == NULL || !FD_ISSET (0, rfds))
bfcf6608
ST
2792 return select (n, rfds, wfds, efds, timeout);
2793
2794 if (wfds == NULL && efds == NULL)
2b187eac 2795 {
bfcf6608
ST
2796 int i;
2797
2798 for (i = 1; i < n; i++)
2799 if (FD_ISSET (i, rfds))
2800 break;
2801 if (i == n)
2802 {
2803 EventTimeout timeout_sec =
2804 (timeout
2805 ? (EMACS_SECS (*timeout) * kEventDurationSecond
2806 + EMACS_USECS (*timeout) * kEventDurationMicrosecond)
2807 : kEventDurationForever);
2808
2809 BLOCK_INPUT;
2810 err = ReceiveNextEvent (0, NULL, timeout_sec,
2811 kEventLeaveInQueue, NULL);
2812 UNBLOCK_INPUT;
2813 if (err == noErr)
96720f09 2814 {
e082ac9d
ST
2815 FD_ZERO (rfds);
2816 FD_SET (0, rfds);
2817 return 1;
96720f09 2818 }
bfcf6608
ST
2819 else
2820 return 0;
2b187eac 2821 }
2b187eac 2822 }
2b187eac 2823
bfcf6608 2824 if (timeout)
2b187eac 2825 {
bfcf6608
ST
2826 remaining_time = *timeout;
2827 EMACS_GET_TIME (now);
2828 EMACS_ADD_TIME (end_time, now, remaining_time);
2b187eac 2829 }
bfcf6608
ST
2830 FD_CLR (0, rfds);
2831 do
2832 {
2833 EMACS_TIME select_timeout;
2834 SELECT_TYPE orfds = *rfds;
2835 int r;
177c0ea7 2836
bfcf6608
ST
2837 EMACS_SET_SECS_USECS (select_timeout, 0, 20000);
2838
2839 if (timeout && EMACS_TIME_LT (remaining_time, select_timeout))
2840 select_timeout = remaining_time;
2841
2842 r = select (n, &orfds, wfds, efds, &select_timeout);
2843 BLOCK_INPUT;
2844 err = ReceiveNextEvent (0, NULL, kEventDurationNoWait,
2845 kEventLeaveInQueue, NULL);
2846 UNBLOCK_INPUT;
2847 if (r > 0)
2848 {
2849 *rfds = orfds;
2850 if (err == noErr)
2851 {
2852 FD_SET (0, rfds);
2853 r++;
2854 }
2855 return r;
2856 }
2857 else if (err == noErr)
2858 {
2859 FD_ZERO (rfds);
2860 FD_SET (0, rfds);
2861 return 1;
2862 }
1000788b 2863
bfcf6608
ST
2864 if (timeout)
2865 {
2866 EMACS_GET_TIME (now);
2867 EMACS_SUB_TIME (remaining_time, end_time, now);
2868 }
2869 }
2870 while (!timeout || EMACS_TIME_LT (now, end_time));
2871
2872 return 0;
2873}
1000788b
AC
2874
2875/* Set up environment variables so that Emacs can correctly find its
2876 support files when packaged as an application bundle. Directories
2877 placed in /usr/local/share/emacs/<emacs-version>/, /usr/local/bin,
2878 and /usr/local/libexec/emacs/<emacs-version>/<system-configuration>
2879 by `make install' by default can instead be placed in
2880 .../Emacs.app/Contents/Resources/ and
2881 .../Emacs.app/Contents/MacOS/. Each of these environment variables
2882 is changed only if it is not already set. Presumably if the user
2883 sets an environment variable, he will want to use files in his path
2884 instead of ones in the application bundle. */
2885void
2886init_mac_osx_environment ()
2887{
2888 CFBundleRef bundle;
2889 CFURLRef bundleURL;
2890 CFStringRef cf_app_bundle_pathname;
2891 int app_bundle_pathname_len;
2892 char *app_bundle_pathname;
2893 char *p, *q;
2894 struct stat st;
2895
2896 /* Fetch the pathname of the application bundle as a C string into
2897 app_bundle_pathname. */
2898
2899 bundle = CFBundleGetMainBundle ();
2900 if (!bundle)
2901 return;
2902
2903 bundleURL = CFBundleCopyBundleURL (bundle);
2904 if (!bundleURL)
2905 return;
2906
2907 cf_app_bundle_pathname = CFURLCopyFileSystemPath (bundleURL,
2908 kCFURLPOSIXPathStyle);
2909 app_bundle_pathname_len = CFStringGetLength (cf_app_bundle_pathname);
2910 app_bundle_pathname = (char *) alloca (app_bundle_pathname_len + 1);
2911
2912 if (!CFStringGetCString (cf_app_bundle_pathname,
2913 app_bundle_pathname,
2914 app_bundle_pathname_len + 1,
2915 kCFStringEncodingISOLatin1))
2916 {
2917 CFRelease (cf_app_bundle_pathname);
2918 return;
2919 }
2920
2921 CFRelease (cf_app_bundle_pathname);
2922
2923 /* P should have sufficient room for the pathname of the bundle plus
2924 the subpath in it leading to the respective directories. Q
2925 should have three times that much room because EMACSLOADPATH can
2926 have the value "<path to lisp dir>:<path to leim dir>:<path to
2927 site-lisp dir>". */
2928 p = (char *) alloca (app_bundle_pathname_len + 50);
2929 q = (char *) alloca (3 * app_bundle_pathname_len + 150);
2930 if (!getenv ("EMACSLOADPATH"))
2931 {
2932 q[0] = '\0';
2933
2934 strcpy (p, app_bundle_pathname);
2935 strcat (p, "/Contents/Resources/lisp");
2936 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
2937 strcat (q, p);
2938
2939 strcpy (p, app_bundle_pathname);
2940 strcat (p, "/Contents/Resources/leim");
2941 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
2942 {
2943 if (q[0] != '\0')
2944 strcat (q, ":");
2945 strcat (q, p);
2946 }
2947
2948 strcpy (p, app_bundle_pathname);
2949 strcat (p, "/Contents/Resources/site-lisp");
2950 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
2951 {
2952 if (q[0] != '\0')
2953 strcat (q, ":");
2954 strcat (q, p);
2955 }
2956
2957 if (q[0] != '\0')
2958 setenv ("EMACSLOADPATH", q, 1);
2959 }
2960
2961 if (!getenv ("EMACSPATH"))
2962 {
2963 q[0] = '\0';
2964
2965 strcpy (p, app_bundle_pathname);
e8f25745 2966 strcat (p, "/Contents/MacOS/libexec");
1000788b
AC
2967 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
2968 strcat (q, p);
2969
2970 strcpy (p, app_bundle_pathname);
e8f25745 2971 strcat (p, "/Contents/MacOS/bin");
1000788b
AC
2972 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
2973 {
2974 if (q[0] != '\0')
2975 strcat (q, ":");
2976 strcat (q, p);
2977 }
2978
2979 if (q[0] != '\0')
2980 setenv ("EMACSPATH", q, 1);
2981 }
2982
2983 if (!getenv ("EMACSDATA"))
2984 {
2985 strcpy (p, app_bundle_pathname);
2986 strcat (p, "/Contents/Resources/etc");
2987 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
2988 setenv ("EMACSDATA", p, 1);
2989 }
2990
2991 if (!getenv ("EMACSDOC"))
2992 {
2993 strcpy (p, app_bundle_pathname);
2994 strcat (p, "/Contents/Resources/etc");
2995 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
2996 setenv ("EMACSDOC", p, 1);
2997 }
2998
2999 if (!getenv ("INFOPATH"))
3000 {
3001 strcpy (p, app_bundle_pathname);
3002 strcat (p, "/Contents/Resources/info");
3003 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
3004 setenv ("INFOPATH", p, 1);
3005 }
3006}
8030369c 3007#endif /* MAC_OSX */
1a578e9b
AC
3008
3009void
3010syms_of_mac ()
3011{
3012 QCLIPBOARD = intern ("CLIPBOARD");
3013 staticpro (&QCLIPBOARD);
7d0393cf 3014
1a578e9b
AC
3015 defsubr (&Smac_paste_function);
3016 defsubr (&Smac_cut_function);
3017 defsubr (&Sx_selection_exists_p);
3018
3019 defsubr (&Sdo_applescript);
60fe1161
AC
3020 defsubr (&Smac_file_name_to_posix);
3021 defsubr (&Sposix_file_name_to_mac);
1a578e9b 3022}
ab5796a9
MB
3023
3024/* arch-tag: 29d30c1f-0c6b-4f88-8a6d-0558d7f9dbff
3025 (do not change this comment) */