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