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