(read_char): Save and restore echo_string when
[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
848int
e0f712ba 849select (n, rfds, wfds, efds, timeout)
1a578e9b
AC
850 int n;
851 SELECT_TYPE *rfds;
852 SELECT_TYPE *wfds;
853 SELECT_TYPE *efds;
854 struct timeval *timeout;
855{
e0f712ba
AC
856#ifdef TARGET_API_MAC_CARBON
857 return 1;
858#else /* not TARGET_API_MAC_CARBON */
1a578e9b
AC
859 EMACS_TIME end_time, now;
860 EventRecord e;
1a578e9b
AC
861
862 /* Can only handle wait for keyboard input. */
863 if (n > 1 || wfds || efds)
864 return -1;
865
866 EMACS_GET_TIME (end_time);
867 EMACS_ADD_TIME (end_time, end_time, *timeout);
7d0393cf 868
1a578e9b
AC
869 do
870 {
871 /* Also return true if an event other than a keyDown has
872 occurred. This causes kbd_buffer_get_event in keyboard.c to
873 call read_avail_input which in turn calls XTread_socket to
874 poll for these events. Otherwise these never get processed
875 except but a very slow poll timer. */
876 if (FD_ISSET (0, rfds) && EventAvail (everyEvent, &e))
877 return 1;
878
879 /* Also check movement of the mouse. */
880 {
881 Point mouse_pos;
882 static Point old_mouse_pos = {-1, -1};
7d0393cf 883
1a578e9b
AC
884 GetMouse (&mouse_pos);
885 if (!EqualPt (mouse_pos, old_mouse_pos))
886 {
887 old_mouse_pos = mouse_pos;
888 return 1;
889 }
890 }
7d0393cf 891
e0f712ba
AC
892 WaitNextEvent (0, &e, 1UL, NULL); /* Accept no event; wait 1
893 tic. by T.I. */
7d0393cf 894
1a578e9b
AC
895 EMACS_GET_TIME (now);
896 EMACS_SUB_TIME (now, end_time, now);
897 }
898 while (!EMACS_TIME_NEG_P (now));
899
900 return 0;
e0f712ba 901#endif /* not TARGET_API_MAC_CARBON */
1a578e9b
AC
902}
903
904
905/* Called in sys_select to wait for an alarm signal to arrive. */
906
907int
908pause ()
909{
fa0b4c14
AC
910 EventRecord e;
911 unsigned long tick;
7d0393cf 912
1a578e9b
AC
913 if (!target_ticks) /* no alarm pending */
914 return -1;
915
e0f712ba
AC
916 if ((tick = TickCount ()) < target_ticks)
917 WaitNextEvent (0, &e, target_ticks - tick, NULL); /* Accept no event;
918 just wait. by T.I. */
7d0393cf 919
1a578e9b
AC
920 target_ticks = 0;
921 if (alarm_signal_func)
922 (*alarm_signal_func)(SIGALRM);
7d0393cf 923
1a578e9b
AC
924 return 0;
925}
926
927
928int
929alarm (int seconds)
930{
931 long remaining = target_ticks ? (TickCount () - target_ticks) / 60 : 0;
7d0393cf 932
1a578e9b 933 target_ticks = seconds ? TickCount () + 60 * seconds : 0;
7d0393cf 934
1a578e9b
AC
935 return (remaining < 0) ? 0 : (unsigned int) remaining;
936}
937
938
939#undef signal
940#ifdef __MRC__
941extern __sigfun signal (int signal, __sigfun signal_func);
942__sigfun
943sys_signal (int signal_num, __sigfun signal_func)
944#elif __MWERKS__
945extern __signal_func_ptr signal (int signal, __signal_func_ptr signal_func);
946__signal_func_ptr
947sys_signal (int signal_num, __signal_func_ptr signal_func)
e0f712ba 948#else /* not __MRC__ and not __MWERKS__ */
1a578e9b 949 You lose!!!
e0f712ba 950#endif /* not __MRC__ and not __MWERKS__ */
1a578e9b
AC
951{
952 if (signal_num != SIGALRM)
953 return signal (signal_num, signal_func);
954 else
955 {
956#ifdef __MRC__
7d0393cf 957 __sigfun old_signal_func;
1a578e9b 958#elif __MWERKS__
7d0393cf 959 __signal_func_ptr old_signal_func;
1a578e9b
AC
960#else
961 You lose!!!
962#endif
963 old_signal_func = alarm_signal_func;
964 alarm_signal_func = signal_func;
965 return old_signal_func;
966 }
967}
968
969
970/* gettimeofday should return the amount of time (in a timeval
971 structure) since midnight today. The toolbox function Microseconds
972 returns the number of microseconds (in a UnsignedWide value) since
973 the machine was booted. Also making this complicated is WideAdd,
974 WideSubtract, etc. take wide values. */
975
976int
977gettimeofday (tp)
978 struct timeval *tp;
979{
980 static inited = 0;
981 static wide wall_clock_at_epoch, clicks_at_epoch;
982 UnsignedWide uw_microseconds;
983 wide w_microseconds;
984 time_t sys_time (time_t *);
985
986 /* If this function is called for the first time, record the number
987 of seconds since midnight and the number of microseconds since
988 boot at the time of this first call. */
989 if (!inited)
990 {
991 time_t systime;
992 inited = 1;
993 systime = sys_time (NULL);
994 /* Store microseconds since midnight in wall_clock_at_epoch. */
995 WideMultiply (systime, 1000000L, &wall_clock_at_epoch);
996 Microseconds (&uw_microseconds);
997 /* Store microseconds since boot in clicks_at_epoch. */
998 clicks_at_epoch.hi = uw_microseconds.hi;
999 clicks_at_epoch.lo = uw_microseconds.lo;
1000 }
1001
1002 /* Get time since boot */
1003 Microseconds (&uw_microseconds);
7d0393cf 1004
1a578e9b
AC
1005 /* Convert to time since midnight*/
1006 w_microseconds.hi = uw_microseconds.hi;
1007 w_microseconds.lo = uw_microseconds.lo;
1008 WideSubtract (&w_microseconds, &clicks_at_epoch);
1009 WideAdd (&w_microseconds, &wall_clock_at_epoch);
1010 tp->tv_sec = WideDivide (&w_microseconds, 1000000L, &tp->tv_usec);
1011
1012 return 0;
1013}
1014
1015
1016#ifdef __MRC__
1017unsigned int
1018sleep (unsigned int seconds)
1019{
bc04fb2c 1020 unsigned long time_up;
fa0b4c14
AC
1021 EventRecord e;
1022
bc04fb2c
AC
1023 time_up = TickCount () + seconds * 60;
1024 while (TickCount () < time_up)
1025 {
1026 /* Accept no event; just wait. by T.I. */
1027 WaitNextEvent (0, &e, 30, NULL);
1028 }
1a578e9b 1029
1a578e9b
AC
1030 return (0);
1031}
1032#endif /* __MRC__ */
1033
1034
1035/* The time functions adjust time values according to the difference
1036 between the Unix and CW epoches. */
1037
1038#undef gmtime
1039extern struct tm *gmtime (const time_t *);
1040struct tm *
1041sys_gmtime (const time_t *timer)
1042{
1043 time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
7d0393cf 1044
1a578e9b
AC
1045 return gmtime (&unix_time);
1046}
1047
1048
1049#undef localtime
1050extern struct tm *localtime (const time_t *);
1051struct tm *
1052sys_localtime (const time_t *timer)
1053{
e0f712ba 1054#if __MSL__ >= 0x6000
1a578e9b
AC
1055 time_t unix_time = *timer;
1056#else
1057 time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
1058#endif
7d0393cf 1059
1a578e9b
AC
1060 return localtime (&unix_time);
1061}
1062
1063
1064#undef ctime
1065extern char *ctime (const time_t *);
1066char *
1067sys_ctime (const time_t *timer)
1068{
e0f712ba 1069#if __MSL__ >= 0x6000
1a578e9b
AC
1070 time_t unix_time = *timer;
1071#else
1072 time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
1073#endif
7d0393cf 1074
1a578e9b
AC
1075 return ctime (&unix_time);
1076}
1077
1078
1079#undef time
1080extern time_t time (time_t *);
1081time_t
1082sys_time (time_t *timer)
1083{
e0f712ba 1084#if __MSL__ >= 0x6000
1a578e9b
AC
1085 time_t mac_time = time (NULL);
1086#else
1087 time_t mac_time = time (NULL) - CW_OR_MPW_UNIX_EPOCH_DIFF;
1088#endif
1089
1090 if (timer)
1091 *timer = mac_time;
7d0393cf 1092
1a578e9b
AC
1093 return mac_time;
1094}
1095
1096
1097/* MPW strftime broken for "%p" format */
1098#ifdef __MRC__
1099#undef strftime
1100#include <time.h>
1101size_t
1102sys_strftime (char * s, size_t maxsize, const char * format,
1103 const struct tm * timeptr)
1104{
1105 if (strcmp (format, "%p") == 0)
1106 {
1107 if (maxsize < 3)
1108 return 0;
1109 if (timeptr->tm_hour < 12)
1110 {
1111 strcpy (s, "AM");
1112 return 2;
1113 }
1114 else
1115 {
1116 strcpy (s, "PM");
1117 return 2;
1118 }
1119 }
1120 else
1121 return strftime (s, maxsize, format, timeptr);
1122}
1123#endif /* __MRC__ */
1124
1125
1126/* no subprocesses, empty wait */
1127
1128int
1129wait (int pid)
1130{
1131 return 0;
1132}
1133
1134
1135void
1136croak (char *badfunc)
1137{
1138 printf ("%s not yet implemented\r\n", badfunc);
1139 exit (1);
1140}
1141
1142
1143char *
1144index (const char * str, int chr)
1145{
1146 return strchr (str, chr);
1147}
1148
1149
1150char *
1151mktemp (char *template)
1152{
1153 int len, k;
1154 static seqnum = 0;
7d0393cf 1155
1a578e9b
AC
1156 len = strlen (template);
1157 k = len - 1;
1158 while (k >= 0 && template[k] == 'X')
1159 k--;
7d0393cf 1160
1a578e9b 1161 k++; /* make k index of first 'X' */
7d0393cf 1162
1a578e9b
AC
1163 if (k < len)
1164 {
1165 /* Zero filled, number of digits equal to the number of X's. */
1166 sprintf (&template[k], "%0*d", len-k, seqnum++);
7d0393cf 1167
1a578e9b
AC
1168 return template;
1169 }
1170 else
7d0393cf 1171 return 0;
1a578e9b
AC
1172}
1173
1174
1175/* Emulate getpwuid, getpwnam and others. */
1176
1177#define PASSWD_FIELD_SIZE 256
1178
1179static char my_passwd_name[PASSWD_FIELD_SIZE];
1180static char my_passwd_dir[MAXPATHLEN+1];
1181
7d0393cf 1182static struct passwd my_passwd =
1a578e9b
AC
1183{
1184 my_passwd_name,
1185 my_passwd_dir,
1186};
1187
49e7a2c0
LH
1188static struct group my_group =
1189{
1190 /* There are no groups on the mac, so we just return "root" as the
1191 group name. */
1192 "root",
1193};
1194
1a578e9b
AC
1195
1196/* Initialized by main () in macterm.c to pathname of emacs directory. */
1197
1198char emacs_passwd_dir[MAXPATHLEN+1];
1199
1200char *
1201getwd (char *);
1202
1203void
1204init_emacs_passwd_dir ()
1205{
1206 int found = false;
1207
1208 if (getwd (emacs_passwd_dir) && getwd (my_passwd_dir))
1209 {
1210 /* Need pathname of first ancestor that begins with "emacs"
1211 since Mac emacs application is somewhere in the emacs-*
1212 tree. */
1213 int len = strlen (emacs_passwd_dir);
1214 int j = len - 1;
1215 /* j points to the "/" following the directory name being
1216 compared. */
1217 int i = j - 1;
1218 while (i >= 0 && !found)
1219 {
1220 while (i >= 0 && emacs_passwd_dir[i] != '/')
1221 i--;
1222 if (emacs_passwd_dir[i] == '/' && i+5 < len)
1223 found = (strncmp (&(emacs_passwd_dir[i+1]), "emacs", 5) == 0);
1224 if (found)
1225 emacs_passwd_dir[j+1] = '\0';
1226 else
1227 {
1228 j = i;
1229 i = j - 1;
1230 }
1231 }
1232 }
7d0393cf 1233
1a578e9b
AC
1234 if (!found)
1235 {
1236 /* Setting to "/" probably won't work but set it to something
1237 anyway. */
1238 strcpy (emacs_passwd_dir, "/");
1239 strcpy (my_passwd_dir, "/");
1240 }
1241}
1242
1243
7d0393cf 1244static struct passwd emacs_passwd =
1a578e9b
AC
1245{
1246 "emacs",
1247 emacs_passwd_dir,
1248};
1249
1250static int my_passwd_inited = 0;
1251
1252
1253static void
1254init_my_passwd ()
1255{
1256 char **owner_name;
1257
1258 /* Note: my_passwd_dir initialized in int_emacs_passwd_dir to
1259 directory where Emacs was started. */
1260
1261 owner_name = (char **) GetResource ('STR ',-16096);
1262 if (owner_name)
1263 {
1264 HLock (owner_name);
1265 BlockMove ((unsigned char *) *owner_name,
1266 (unsigned char *) my_passwd_name,
1267 *owner_name[0]+1);
1268 HUnlock (owner_name);
1269 p2cstr ((unsigned char *) my_passwd_name);
1270 }
1271 else
1272 my_passwd_name[0] = 0;
1273}
1274
1275
1276struct passwd *
1277getpwuid (uid_t uid)
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
49e7a2c0
LH
1289struct group *
1290getgrgid (gid_t gid)
1291{
1292 return &my_group;
1293}
1294
1295
1a578e9b
AC
1296struct passwd *
1297getpwnam (const char *name)
1298{
1299 if (strcmp (name, "emacs") == 0)
1300 return &emacs_passwd;
1301
1302 if (!my_passwd_inited)
7d0393cf 1303 {
1a578e9b
AC
1304 init_my_passwd ();
1305 my_passwd_inited = 1;
1306 }
7d0393cf 1307
1a578e9b
AC
1308 return &my_passwd;
1309}
1310
1311
1312/* The functions fork, kill, sigsetmask, sigblock, request_sigio,
1313 setpgrp, setpriority, and unrequest_sigio are defined to be empty
1314 as in msdos.c. */
1315
1316
1317int
1318fork ()
1319{
1320 return -1;
1321}
1322
1323
1324int
1325kill (int x, int y)
1326{
1327 return -1;
1328}
1329
1330
1331void
1332sys_subshell ()
1333{
1334 error ("Can't spawn subshell");
1335}
1336
1337
1338int
1339sigsetmask (int x)
1340{
1341 return 0;
1342}
1343
1344
1345int
1346sigblock (int mask)
1347{
1348 return 0;
7d0393cf 1349}
1a578e9b
AC
1350
1351
1352void
1353request_sigio (void)
1354{
1355}
1356
1357
1358void
1359unrequest_sigio (void)
1360{
1361}
1362
1363
1364int
1365setpgrp ()
1366{
1367 return 0;
1368}
1369
1370
1371/* No pipes yet. */
1372
1373int
1374pipe (int _fildes[2])
1375{
1376 errno = EACCES;
1377 return -1;
1378}
1379
1380
1381/* Hard and symbolic links. */
1382
1383int
1384symlink (const char *name1, const char *name2)
1385{
1386 errno = ENOENT;
1387 return -1;
1388}
1389
1390
1391int
1392link (const char *name1, const char *name2)
1393{
1394 errno = ENOENT;
1395 return -1;
1396}
1397
e0f712ba 1398#endif /* ! MAC_OSX */
1a578e9b
AC
1399
1400/* Determine the path name of the file specified by VREFNUM, DIRID,
1401 and NAME and place that in the buffer PATH of length
1402 MAXPATHLEN. */
1403int
1404path_from_vol_dir_name (char *path, int man_path_len, short vol_ref_num,
1405 long dir_id, ConstStr255Param name)
1406{
1407 Str255 dir_name;
1408 CInfoPBRec cipb;
1409 OSErr err;
1410
1411 if (strlen (name) > man_path_len)
1412 return 0;
1413
1414 memcpy (dir_name, name, name[0]+1);
1415 memcpy (path, name, name[0]+1);
1416 p2cstr (path);
1417
1418 cipb.dirInfo.ioDrParID = dir_id;
1419 cipb.dirInfo.ioNamePtr = dir_name;
1420
1421 do
1422 {
1423 cipb.dirInfo.ioVRefNum = vol_ref_num;
1424 cipb.dirInfo.ioFDirIndex = -1;
1425 cipb.dirInfo.ioDrDirID = cipb.dirInfo.ioDrParID;
1426 /* go up to parent each time */
1427
1428 err = PBGetCatInfo (&cipb, false);
1429 if (err != noErr)
1430 return 0;
7d0393cf 1431
1a578e9b
AC
1432 p2cstr (dir_name);
1433 if (strlen (dir_name) + strlen (path) + 1 >= man_path_len)
1434 return 0;
1435
1436 strcat (dir_name, ":");
1437 strcat (dir_name, path);
1438 /* attach to front since we're going up directory tree */
1439 strcpy (path, dir_name);
1440 }
1441 while (cipb.dirInfo.ioDrDirID != fsRtDirID);
1442 /* stop when we see the volume's root directory */
7d0393cf 1443
1a578e9b
AC
1444 return 1; /* success */
1445}
1446
e0f712ba 1447#ifndef MAC_OSX
1a578e9b
AC
1448
1449int
1450readlink (const char *path, char *buf, int bufsiz)
1451{
1452 char mac_sym_link_name[MAXPATHLEN+1];
1453 OSErr err;
1454 FSSpec fsspec;
1455 Boolean target_is_folder, was_aliased;
1456 Str255 directory_name, mac_pathname;
1457 CInfoPBRec cipb;
1458
60fe1161 1459 if (posix_to_mac_pathname (path, mac_sym_link_name, MAXPATHLEN+1) == 0)
1a578e9b
AC
1460 return -1;
1461
1462 c2pstr (mac_sym_link_name);
1463 err = FSMakeFSSpec (0, 0, mac_sym_link_name, &fsspec);
1464 if (err != noErr)
1465 {
1466 errno = ENOENT;
1467 return -1;
1468 }
1469
1470 err = ResolveAliasFile (&fsspec, true, &target_is_folder, &was_aliased);
1471 if (err != noErr || !was_aliased)
1472 {
1473 errno = ENOENT;
1474 return -1;
1475 }
1476
1477 if (path_from_vol_dir_name (mac_pathname, 255, fsspec.vRefNum, fsspec.parID,
1478 fsspec.name) == 0)
1479 {
1480 errno = ENOENT;
1481 return -1;
1482 }
1483
60fe1161 1484 if (mac_to_posix_pathname (mac_pathname, buf, bufsiz) == 0)
1a578e9b
AC
1485 {
1486 errno = ENOENT;
1487 return -1;
1488 }
1489
1490 return strlen (buf);
1491}
1492
1493
1494/* Convert a path to one with aliases fully expanded. */
1495
1496static int
1497find_true_pathname (const char *path, char *buf, int bufsiz)
1498{
1499 char *q, temp[MAXPATHLEN+1];
1500 const char *p;
1501 int len;
1502
1503 if (bufsiz <= 0 || path == 0 || path[0] == '\0')
1504 return -1;
1505
1506 buf[0] = '\0';
7d0393cf 1507
1a578e9b
AC
1508 p = path;
1509 if (*p == '/')
1510 q = strchr (p + 1, '/');
1511 else
1512 q = strchr (p, '/');
1513 len = 0; /* loop may not be entered, e.g., for "/" */
1514
1515 while (q)
1516 {
1517 strcpy (temp, buf);
1518 strncat (temp, p, q - p);
1519 len = readlink (temp, buf, bufsiz);
1520 if (len <= -1)
1521 {
1522 if (strlen (temp) + 1 > bufsiz)
1523 return -1;
1524 strcpy (buf, temp);
1525 }
1526 strcat (buf, "/");
1527 len++;
1528 p = q + 1;
1529 q = strchr(p, '/');
1530 }
7d0393cf 1531
1a578e9b
AC
1532 if (len + strlen (p) + 1 >= bufsiz)
1533 return -1;
7d0393cf 1534
1a578e9b
AC
1535 strcat (buf, p);
1536 return len + strlen (p);
1537}
1538
1539
1540mode_t
1541umask (mode_t numask)
1542{
1543 static mode_t mask = 022;
1544 mode_t oldmask = mask;
1545 mask = numask;
1546 return oldmask;
1547}
1548
1549
1550int
1551chmod (const char *path, mode_t mode)
1552{
1553 /* say it always succeed for now */
1554 return 0;
1555}
1556
1557
1558int
1559dup (int oldd)
1560{
1561#ifdef __MRC__
1562 return fcntl (oldd, F_DUPFD, 0);
1563#elif __MWERKS__
1564 /* current implementation of fcntl in fcntl.mac.c simply returns old
1565 descriptor */
1566 return fcntl (oldd, F_DUPFD);
1567#else
1568You lose!!!
1569#endif
1570}
1571
1572
1573/* This is from the original sysdep.c. Emulate BSD dup2. First close
1574 newd if it already exists. Then, attempt to dup oldd. If not
1575 successful, call dup2 recursively until we are, then close the
1576 unsuccessful ones. */
1577
1578int
1579dup2 (int oldd, int newd)
1580{
1581 int fd, ret;
7d0393cf 1582
1a578e9b
AC
1583 close (newd);
1584
1585 fd = dup (oldd);
1586 if (fd == -1)
1587 return -1;
1588 if (fd == newd)
1589 return newd;
1590 ret = dup2 (oldd, newd);
1591 close (fd);
1592 return ret;
1593}
1594
1595
1596/* let it fail for now */
1597
1598char *
1599sbrk (int incr)
1600{
1601 return (char *) -1;
1602}
1603
1604
1605int
1606fsync (int fd)
1607{
1608 return 0;
1609}
1610
1611
1612int
1613ioctl (int d, int request, void *argp)
1614{
1615 return -1;
1616}
1617
1618
1619#ifdef __MRC__
1620int
1621isatty (int fildes)
1622{
1623 if (fildes >=0 && fildes <= 2)
1624 return 1;
1625 else
1626 return 0;
1627}
1628
1629
1630int
1631getgid ()
1632{
1633 return 100;
1634}
1635
1636
1637int
1638getegid ()
1639{
1640 return 100;
1641}
1642
1643
1644int
1645getuid ()
1646{
1647 return 200;
1648}
1649
1650
1651int
1652geteuid ()
1653{
1654 return 200;
1655}
1656#endif /* __MRC__ */
1657
1658
1659#ifdef __MWERKS__
e0f712ba 1660#if __MSL__ < 0x6000
1a578e9b
AC
1661#undef getpid
1662int
1663getpid ()
1664{
1665 return 9999;
1666}
1667#endif
1668#endif /* __MWERKS__ */
1669
e0f712ba
AC
1670#endif /* ! MAC_OSX */
1671
1a578e9b
AC
1672
1673/* Return the path to the directory in which Emacs can create
1674 temporary files. The MacOS "temporary items" directory cannot be
1675 used because it removes the file written by a process when it
1676 exits. In that sense it's more like "/dev/null" than "/tmp" (but
1677 again not exactly). And of course Emacs needs to read back the
1678 files written by its subprocesses. So here we write the files to a
1679 directory "Emacs" in the Preferences Folder. This directory is
1680 created if it does not exist. */
1681
e0f712ba 1682char *
1a578e9b
AC
1683get_temp_dir_name ()
1684{
1685 static char *temp_dir_name = NULL;
1686 short vol_ref_num;
1687 long dir_id;
1688 OSErr err;
1689 Str255 dir_name, full_path;
1690 CInfoPBRec cpb;
1691 char unix_dir_name[MAXPATHLEN+1];
1692 DIR *dir;
7d0393cf 1693
1a578e9b
AC
1694 /* Cache directory name with pointer temp_dir_name.
1695 Look for it only the first time. */
1696 if (!temp_dir_name)
1697 {
1698 err = FindFolder (kOnSystemDisk, kPreferencesFolderType, kCreateFolder,
1699 &vol_ref_num, &dir_id);
1700 if (err != noErr)
1701 return NULL;
7d0393cf 1702
1a578e9b
AC
1703 if (!path_from_vol_dir_name (full_path, 255, vol_ref_num, dir_id, "\p"))
1704 return NULL;
1705
1706 if (strlen (full_path) + 6 <= MAXPATHLEN)
1707 strcat (full_path, "Emacs:");
7d0393cf 1708 else
1a578e9b
AC
1709 return NULL;
1710
60fe1161 1711 if (!mac_to_posix_pathname (full_path, unix_dir_name, MAXPATHLEN+1))
1a578e9b 1712 return NULL;
7d0393cf 1713
1a578e9b
AC
1714 dir = opendir (unix_dir_name); /* check whether temp directory exists */
1715 if (dir)
1716 closedir (dir);
1717 else if (mkdir (unix_dir_name, 0700) != 0) /* create it if not */
1718 return NULL;
1719
1720 temp_dir_name = (char *) malloc (strlen (unix_dir_name) + 1);
1721 strcpy (temp_dir_name, unix_dir_name);
1722 }
1723
1724 return temp_dir_name;
1725}
1726
e0f712ba 1727#ifndef MAC_OSX
1a578e9b
AC
1728
1729/* Allocate and construct an array of pointers to strings from a list
1730 of strings stored in a 'STR#' resource. The returned pointer array
1731 is stored in the style of argv and environ: if the 'STR#' resource
7d0393cf 1732 contains numString strings, a pointer array with numString+1
1a578e9b
AC
1733 elements is returned in which the last entry contains a null
1734 pointer. The pointer to the pointer array is passed by pointer in
1735 parameter t. The resource ID of the 'STR#' resource is passed in
1736 parameter StringListID.
1737 */
1738
1739void
1740get_string_list (char ***t, short string_list_id)
1741{
1742 Handle h;
1743 Ptr p;
1744 int i, num_strings;
1745
1746 h = GetResource ('STR#', string_list_id);
1747 if (h)
1748 {
1749 HLock (h);
1750 p = *h;
1751 num_strings = * (short *) p;
1752 p += sizeof(short);
1753 *t = (char **) malloc (sizeof (char *) * (num_strings + 1));
1754 for (i = 0; i < num_strings; i++)
1755 {
1756 short length = *p++;
1757 (*t)[i] = (char *) malloc (length + 1);
1758 strncpy ((*t)[i], p, length);
1759 (*t)[i][length] = '\0';
1760 p += length;
1761 }
1762 (*t)[num_strings] = 0;
1763 HUnlock (h);
1764 }
1765 else
1766 {
1767 /* Return no string in case GetResource fails. Bug fixed by
1768 Ikegami Tsutomu. Caused MPW build to crash without sym -on
1769 option (no sym -on implies -opt local). */
1770 *t = (char **) malloc (sizeof (char *));
1771 (*t)[0] = 0;
1772 }
1773}
1774
1775
1776static char *
1777get_path_to_system_folder ()
1778{
1779 short vol_ref_num;
1780 long dir_id;
1781 OSErr err;
1782 Str255 dir_name, full_path;
1783 CInfoPBRec cpb;
1784 static char system_folder_unix_name[MAXPATHLEN+1];
1785 DIR *dir;
7d0393cf 1786
1a578e9b
AC
1787 err = FindFolder (kOnSystemDisk, kSystemFolderType, kDontCreateFolder,
1788 &vol_ref_num, &dir_id);
1789 if (err != noErr)
1790 return NULL;
7d0393cf 1791
1a578e9b
AC
1792 if (!path_from_vol_dir_name (full_path, 255, vol_ref_num, dir_id, "\p"))
1793 return NULL;
1794
e0f712ba
AC
1795 if (!mac_to_posix_pathname (full_path, system_folder_unix_name,
1796 MAXPATHLEN+1))
1a578e9b 1797 return NULL;
7d0393cf 1798
1a578e9b
AC
1799 return system_folder_unix_name;
1800}
1801
1802
1803char **environ;
1804
1805#define ENVIRON_STRING_LIST_ID 128
1806
1807/* Get environment variable definitions from STR# resource. */
1808
1809void
1810init_environ ()
1811{
1812 int i;
7d0393cf 1813
1a578e9b
AC
1814 get_string_list (&environ, ENVIRON_STRING_LIST_ID);
1815
1816 i = 0;
1817 while (environ[i])
1818 i++;
1819
1820 /* Make HOME directory the one Emacs starts up in if not specified
1821 by resource. */
1822 if (getenv ("HOME") == NULL)
1823 {
1824 environ = (char **) realloc (environ, sizeof (char *) * (i + 2));
1825 if (environ)
1826 {
1827 environ[i] = (char *) malloc (strlen (my_passwd_dir) + 6);
1828 if (environ[i])
1829 {
1830 strcpy (environ[i], "HOME=");
1831 strcat (environ[i], my_passwd_dir);
1832 }
1833 environ[i+1] = 0;
1834 i++;
1835 }
1836 }
1837
1838 /* Make HOME directory the one Emacs starts up in if not specified
1839 by resource. */
1840 if (getenv ("MAIL") == NULL)
1841 {
1842 environ = (char **) realloc (environ, sizeof (char *) * (i + 2));
1843 if (environ)
1844 {
1845 char * path_to_system_folder = get_path_to_system_folder ();
1846 environ[i] = (char *) malloc (strlen (path_to_system_folder) + 22);
1847 if (environ[i])
1848 {
1849 strcpy (environ[i], "MAIL=");
1850 strcat (environ[i], path_to_system_folder);
1851 strcat (environ[i], "Eudora Folder/In");
1852 }
1853 environ[i+1] = 0;
1854 }
1855 }
1856}
1857
1858
1859/* Return the value of the environment variable NAME. */
1860
1861char *
1862getenv (const char *name)
1863{
1864 int length = strlen(name);
1865 char **e;
1866
1867 for (e = environ; *e != 0; e++)
1868 if (strncmp(*e, name, length) == 0 && (*e)[length] == '=')
1869 return &(*e)[length + 1];
1870
1871 if (strcmp (name, "TMPDIR") == 0)
1872 return get_temp_dir_name ();
1873
1874 return 0;
1875}
1876
1877
1878#ifdef __MRC__
1879/* see Interfaces&Libraries:Interfaces:CIncludes:signal.h */
1880char *sys_siglist[] =
1881{
1882 "Zero is not a signal!!!",
1883 "Abort", /* 1 */
1884 "Interactive user interrupt", /* 2 */ "?",
1885 "Floating point exception", /* 4 */ "?", "?", "?",
1886 "Illegal instruction", /* 8 */ "?", "?", "?", "?", "?", "?", "?",
1887 "Segment violation", /* 16 */ "?", "?", "?", "?", "?", "?", "?",
1888 "?", "?", "?", "?", "?", "?", "?", "?",
1889 "Terminal" /* 32 */
1890};
1891#elif __MWERKS__
1892char *sys_siglist[] =
1893{
1894 "Zero is not a signal!!!",
1895 "Abort",
1896 "Floating point exception",
1897 "Illegal instruction",
1898 "Interactive user interrupt",
1899 "Segment violation",
1900 "Terminal"
1901};
e0f712ba 1902#else /* not __MRC__ and not __MWERKS__ */
1a578e9b 1903You lose!!!
e0f712ba 1904#endif /* not __MRC__ and not __MWERKS__ */
1a578e9b
AC
1905
1906
1907#include <utsname.h>
1908
1909int
1910uname (struct utsname *name)
1911{
1912 char **system_name;
1913 system_name = GetString (-16413); /* IM - Resource Manager Reference */
1914 if (system_name)
1915 {
1916 BlockMove (*system_name, name->nodename, (*system_name)[0]+1);
1917 p2cstr (name->nodename);
1918 return 0;
1919 }
1920 else
1921 return -1;
1922}
1923
1924
1925#include <Processes.h>
1926#include <EPPC.h>
1927
1928/* Event class of HLE sent to subprocess. */
1929const OSType kEmacsSubprocessSend = 'ESND';
1930
1931/* Event class of HLE sent back from subprocess. */
1932const OSType kEmacsSubprocessReply = 'ERPY';
1933
1934
1935char *
1936mystrchr (char *s, char c)
1937{
1938 while (*s && *s != c)
1939 {
1940 if (*s == '\\')
1941 s++;
1942 s++;
1943 }
1944
1945 if (*s)
1946 {
1947 *s = '\0';
1948 return s;
1949 }
1950 else
1951 return NULL;
1952}
1953
1954
1955char *
1956mystrtok (char *s)
7d0393cf 1957{
1a578e9b
AC
1958 while (*s)
1959 s++;
1960
1961 return s + 1;
1962}
1963
1964
1965void
1966mystrcpy (char *to, char *from)
1967{
1968 while (*from)
1969 {
1970 if (*from == '\\')
1971 from++;
1972 *to++ = *from++;
1973 }
1974 *to = '\0';
1975}
1976
1977
1978/* Start a Mac subprocess. Arguments for it is passed in argv (null
1979 terminated). The process should run with the default directory
1980 "workdir", read input from "infn", and write output and error to
1981 "outfn" and "errfn", resp. The Process Manager call
1982 LaunchApplication is used to start the subprocess. We use high
1983 level events as the mechanism to pass arguments to the subprocess
1984 and to make Emacs wait for the subprocess to terminate and pass
1985 back a result code. The bulk of the code here packs the arguments
1986 into one message to be passed together with the high level event.
1987 Emacs also sometimes starts a subprocess using a shell to perform
1988 wildcard filename expansion. Since we don't really have a shell on
1989 the Mac, this case is detected and the starting of the shell is
1990 by-passed. We really need to add code here to do filename
1991 expansion to support such functionality. */
1992
1993int
1994run_mac_command (argv, workdir, infn, outfn, errfn)
1995 unsigned char **argv;
1996 const char *workdir;
1997 const char *infn, *outfn, *errfn;
1998{
e0f712ba
AC
1999#ifdef TARGET_API_MAC_CARBON
2000 return -1;
2001#else /* not TARGET_API_MAC_CARBON */
1a578e9b
AC
2002 char macappname[MAXPATHLEN+1], macworkdir[MAXPATHLEN+1];
2003 char macinfn[MAXPATHLEN+1], macoutfn[MAXPATHLEN+1], macerrfn[MAXPATHLEN+1];
2004 int paramlen, argc, newargc, j, retries;
2005 char **newargv, *param, *p;
2006 OSErr iErr;
2007 FSSpec spec;
2008 LaunchParamBlockRec lpbr;
2009 EventRecord send_event, reply_event;
2010 RgnHandle cursor_region_handle;
2011 TargetID targ;
2012 unsigned long ref_con, len;
7d0393cf 2013
60fe1161 2014 if (posix_to_mac_pathname (workdir, macworkdir, MAXPATHLEN+1) == 0)
1a578e9b 2015 return -1;
60fe1161 2016 if (posix_to_mac_pathname (infn, macinfn, MAXPATHLEN+1) == 0)
1a578e9b 2017 return -1;
60fe1161 2018 if (posix_to_mac_pathname (outfn, macoutfn, MAXPATHLEN+1) == 0)
1a578e9b 2019 return -1;
60fe1161 2020 if (posix_to_mac_pathname (errfn, macerrfn, MAXPATHLEN+1) == 0)
1a578e9b 2021 return -1;
7d0393cf 2022
1a578e9b
AC
2023 paramlen = strlen (macworkdir) + strlen (macinfn) + strlen (macoutfn)
2024 + strlen (macerrfn) + 4; /* count nulls at end of strings */
2025
2026 argc = 0;
2027 while (argv[argc])
2028 argc++;
2029
2030 if (argc == 0)
2031 return -1;
2032
2033 /* If a subprocess is invoked with a shell, we receive 3 arguments
2034 of the form: "<path to emacs bins>/sh" "-c" "<path to emacs
2035 bins>/<command> <command args>" */
2036 j = strlen (argv[0]);
2037 if (j >= 3 && strcmp (argv[0]+j-3, "/sh") == 0
2038 && argc == 3 && strcmp (argv[1], "-c") == 0)
2039 {
2040 char *command, *t, tempmacpathname[MAXPATHLEN+1];
7d0393cf 2041
1a578e9b
AC
2042 /* The arguments for the command in argv[2] are separated by
2043 spaces. Count them and put the count in newargc. */
2044 command = (char *) alloca (strlen (argv[2])+2);
2045 strcpy (command, argv[2]);
2046 if (command[strlen (command) - 1] != ' ')
2047 strcat (command, " ");
7d0393cf 2048
1a578e9b
AC
2049 t = command;
2050 newargc = 0;
2051 t = mystrchr (t, ' ');
2052 while (t)
2053 {
2054 newargc++;
2055 t = mystrchr (t+1, ' ');
2056 }
7d0393cf 2057
1a578e9b 2058 newargv = (char **) alloca (sizeof (char *) * newargc);
7d0393cf 2059
1a578e9b
AC
2060 t = command;
2061 for (j = 0; j < newargc; j++)
2062 {
2063 newargv[j] = (char *) alloca (strlen (t) + 1);
2064 mystrcpy (newargv[j], t);
2065
2066 t = mystrtok (t);
2067 paramlen += strlen (newargv[j]) + 1;
2068 }
7d0393cf 2069
1a578e9b
AC
2070 if (strncmp (newargv[0], "~emacs/", 7) == 0)
2071 {
60fe1161 2072 if (posix_to_mac_pathname (newargv[0], tempmacpathname, MAXPATHLEN+1)
1a578e9b
AC
2073 == 0)
2074 return -1;
2075 }
2076 else
2077 { /* sometimes Emacs call "sh" without a path for the command */
2078#if 0
2079 char *t = (char *) alloca (strlen (newargv[0]) + 7 + 1);
2080 strcpy (t, "~emacs/");
2081 strcat (t, newargv[0]);
e0f712ba 2082#endif /* 0 */
1a578e9b 2083 Lisp_Object path;
e0f712ba 2084 openp (Vexec_path, build_string (newargv[0]), EXEC_SUFFIXES, &path,
141f653a 2085 make_number (X_OK));
1a578e9b
AC
2086
2087 if (NILP (path))
2088 return -1;
d5db4077 2089 if (posix_to_mac_pathname (SDATA (path), tempmacpathname,
1a578e9b
AC
2090 MAXPATHLEN+1) == 0)
2091 return -1;
2092 }
2093 strcpy (macappname, tempmacpathname);
2094 }
2095 else
7d0393cf 2096 {
60fe1161 2097 if (posix_to_mac_pathname (argv[0], macappname, MAXPATHLEN+1) == 0)
1a578e9b
AC
2098 return -1;
2099
2100 newargv = (char **) alloca (sizeof (char *) * argc);
7d0393cf 2101 newargc = argc;
1a578e9b
AC
2102 for (j = 1; j < argc; j++)
2103 {
2104 if (strncmp (argv[j], "~emacs/", 7) == 0)
2105 {
2106 char *t = strchr (argv[j], ' ');
2107 if (t)
2108 {
2109 char tempcmdname[MAXPATHLEN+1], tempmaccmdname[MAXPATHLEN+1];
2110 strncpy (tempcmdname, argv[j], t-argv[j]);
2111 tempcmdname[t-argv[j]] = '\0';
60fe1161 2112 if (posix_to_mac_pathname (tempcmdname, tempmaccmdname,
1a578e9b
AC
2113 MAXPATHLEN+1) == 0)
2114 return -1;
2115 newargv[j] = (char *) alloca (strlen (tempmaccmdname)
2116 + strlen (t) + 1);
2117 strcpy (newargv[j], tempmaccmdname);
2118 strcat (newargv[j], t);
2119 }
2120 else
2121 {
2122 char tempmaccmdname[MAXPATHLEN+1];
60fe1161 2123 if (posix_to_mac_pathname (argv[j], tempmaccmdname,
1a578e9b
AC
2124 MAXPATHLEN+1) == 0)
2125 return -1;
2126 newargv[j] = (char *) alloca (strlen (tempmaccmdname)+1);
2127 strcpy (newargv[j], tempmaccmdname);
2128 }
2129 }
2130 else
7d0393cf 2131 newargv[j] = argv[j];
1a578e9b
AC
2132 paramlen += strlen (newargv[j]) + 1;
2133 }
2134 }
2135
2136 /* After expanding all the arguments, we now know the length of the
2137 parameter block to be sent to the subprocess as a message
2138 attached to the HLE. */
2139 param = (char *) malloc (paramlen + 1);
2140 if (!param)
2141 return -1;
2142
2143 p = param;
2144 *p++ = newargc;
2145 /* first byte of message contains number of arguments for command */
2146 strcpy (p, macworkdir);
2147 p += strlen (macworkdir);
2148 *p++ = '\0';
2149 /* null terminate strings sent so it's possible to use strcpy over there */
2150 strcpy (p, macinfn);
2151 p += strlen (macinfn);
7d0393cf 2152 *p++ = '\0';
1a578e9b
AC
2153 strcpy (p, macoutfn);
2154 p += strlen (macoutfn);
7d0393cf 2155 *p++ = '\0';
1a578e9b
AC
2156 strcpy (p, macerrfn);
2157 p += strlen (macerrfn);
7d0393cf 2158 *p++ = '\0';
1a578e9b
AC
2159 for (j = 1; j < newargc; j++)
2160 {
2161 strcpy (p, newargv[j]);
2162 p += strlen (newargv[j]);
7d0393cf 2163 *p++ = '\0';
1a578e9b 2164 }
7d0393cf 2165
1a578e9b 2166 c2pstr (macappname);
7d0393cf 2167
1a578e9b 2168 iErr = FSMakeFSSpec (0, 0, macappname, &spec);
7d0393cf 2169
1a578e9b
AC
2170 if (iErr != noErr)
2171 {
2172 free (param);
2173 return -1;
2174 }
2175
2176 lpbr.launchBlockID = extendedBlock;
2177 lpbr.launchEPBLength = extendedBlockLen;
2178 lpbr.launchControlFlags = launchContinue + launchNoFileFlags;
2179 lpbr.launchAppSpec = &spec;
2180 lpbr.launchAppParameters = NULL;
2181
2182 iErr = LaunchApplication (&lpbr); /* call the subprocess */
2183 if (iErr != noErr)
2184 {
2185 free (param);
2186 return -1;
2187 }
2188
2189 send_event.what = kHighLevelEvent;
2190 send_event.message = kEmacsSubprocessSend;
2191 /* Event ID stored in "where" unused */
2192
2193 retries = 3;
2194 /* OS may think current subprocess has terminated if previous one
2195 terminated recently. */
2196 do
2197 {
2198 iErr = PostHighLevelEvent (&send_event, &lpbr.launchProcessSN, 0, param,
2199 paramlen + 1, receiverIDisPSN);
2200 }
2201 while (iErr == sessClosedErr && retries-- > 0);
2202
2203 if (iErr != noErr)
2204 {
2205 free (param);
2206 return -1;
2207 }
2208
2209 cursor_region_handle = NewRgn ();
7d0393cf 2210
1a578e9b
AC
2211 /* Wait for the subprocess to finish, when it will send us a ERPY
2212 high level event. */
2213 while (1)
2214 if (WaitNextEvent (highLevelEventMask, &reply_event, 180,
2215 cursor_region_handle)
2216 && reply_event.message == kEmacsSubprocessReply)
2217 break;
7d0393cf 2218
1a578e9b
AC
2219 /* The return code is sent through the refCon */
2220 iErr = AcceptHighLevelEvent (&targ, &ref_con, NULL, &len);
2221 if (iErr != noErr)
2222 {
2223 DisposeHandle ((Handle) cursor_region_handle);
2224 free (param);
2225 return -1;
2226 }
7d0393cf 2227
1a578e9b
AC
2228 DisposeHandle ((Handle) cursor_region_handle);
2229 free (param);
2230
2231 return ref_con;
e0f712ba 2232#endif /* not TARGET_API_MAC_CARBON */
1a578e9b
AC
2233}
2234
2235
2236DIR *
2237opendir (const char *dirname)
2238{
7d0393cf 2239 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
1a578e9b
AC
2240 char mac_pathname[MAXPATHLEN+1], vol_name[MAXPATHLEN+1];
2241 DIR *dirp;
2242 CInfoPBRec cipb;
2243 HVolumeParam vpb;
2244 int len, vol_name_len;
7d0393cf 2245
1a578e9b
AC
2246 if (find_true_pathname (dirname, true_pathname, MAXPATHLEN+1) == -1)
2247 return 0;
7d0393cf 2248
1a578e9b
AC
2249 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
2250 if (len > -1)
2251 fully_resolved_name[len] = '\0';
2252 else
2253 strcpy (fully_resolved_name, true_pathname);
2254
2255 dirp = (DIR *) malloc (sizeof(DIR));
2256 if (!dirp)
2257 return 0;
2258
2259 /* Handle special case when dirname is "/": sets up for readir to
2260 get all mount volumes. */
2261 if (strcmp (fully_resolved_name, "/") == 0)
2262 {
2263 dirp->getting_volumes = 1; /* special all mounted volumes DIR struct */
2264 dirp->current_index = 1; /* index for first volume */
2265 return dirp;
2266 }
2267
2268 /* Handle typical cases: not accessing all mounted volumes. */
60fe1161 2269 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
1a578e9b
AC
2270 return 0;
2271
2272 /* Emacs calls opendir without the trailing '/', Mac needs trailing ':' */
2273 len = strlen (mac_pathname);
2274 if (mac_pathname[len - 1] != ':' && len < MAXPATHLEN)
2275 strcat (mac_pathname, ":");
7d0393cf 2276
1a578e9b
AC
2277 /* Extract volume name */
2278 vol_name_len = strchr (mac_pathname, ':') - mac_pathname;
2279 strncpy (vol_name, mac_pathname, vol_name_len);
2280 vol_name[vol_name_len] = '\0';
2281 strcat (vol_name, ":");
2282
2283 c2pstr (mac_pathname);
2284 cipb.hFileInfo.ioNamePtr = mac_pathname;
2285 /* using full pathname so vRefNum and DirID ignored */
2286 cipb.hFileInfo.ioVRefNum = 0;
2287 cipb.hFileInfo.ioDirID = 0;
2288 cipb.hFileInfo.ioFDirIndex = 0;
2289 /* set to 0 to get information about specific dir or file */
7d0393cf 2290
1a578e9b
AC
2291 errno = PBGetCatInfo (&cipb, false);
2292 if (errno != noErr)
2293 {
2294 errno = ENOENT;
2295 return 0;
2296 }
2297
2298 if (!(cipb.hFileInfo.ioFlAttrib & 0x10)) /* bit 4 = 1 for directories */
2299 return 0; /* not a directory */
2300
2301 dirp->dir_id = cipb.dirInfo.ioDrDirID; /* used later in readdir */
2302 dirp->getting_volumes = 0;
2303 dirp->current_index = 1; /* index for first file/directory */
2304
2305 c2pstr (vol_name);
2306 vpb.ioNamePtr = vol_name;
2307 /* using full pathname so vRefNum and DirID ignored */
2308 vpb.ioVRefNum = 0;
2309 vpb.ioVolIndex = -1;
2310 errno = PBHGetVInfo ((union HParamBlockRec *) &vpb, false);
2311 if (errno != noErr)
2312 {
2313 errno = ENOENT;
2314 return 0;
2315 }
2316
2317 dirp->vol_ref_num = vpb.ioVRefNum;
7d0393cf 2318
1a578e9b
AC
2319 return dirp;
2320}
2321
2322int
2323closedir (DIR *dp)
2324{
2325 free (dp);
2326
2327 return 0;
2328}
2329
2330
2331struct dirent *
2332readdir (DIR *dp)
2333{
2334 HParamBlockRec hpblock;
2335 CInfoPBRec cipb;
2336 static struct dirent s_dirent;
2337 static Str255 s_name;
2338 int done;
2339 char *p;
2340
2341 /* Handle the root directory containing the mounted volumes. Call
2342 PBHGetVInfo specifying an index to obtain the info for a volume.
2343 PBHGetVInfo returns an error when it receives an index beyond the
2344 last volume, at which time we should return a nil dirent struct
2345 pointer. */
2346 if (dp->getting_volumes)
2347 {
2348 hpblock.volumeParam.ioNamePtr = s_name;
2349 hpblock.volumeParam.ioVRefNum = 0;
2350 hpblock.volumeParam.ioVolIndex = dp->current_index;
7d0393cf 2351
1a578e9b
AC
2352 errno = PBHGetVInfo (&hpblock, false);
2353 if (errno != noErr)
2354 {
2355 errno = ENOENT;
2356 return 0;
2357 }
7d0393cf 2358
1a578e9b
AC
2359 p2cstr (s_name);
2360 strcat (s_name, "/"); /* need "/" for stat to work correctly */
2361
2362 dp->current_index++;
2363
2364 s_dirent.d_ino = hpblock.volumeParam.ioVRefNum;
2365 s_dirent.d_name = s_name;
7d0393cf 2366
1a578e9b
AC
2367 return &s_dirent;
2368 }
2369 else
2370 {
2371 cipb.hFileInfo.ioVRefNum = dp->vol_ref_num;
2372 cipb.hFileInfo.ioNamePtr = s_name;
2373 /* location to receive filename returned */
2374
2375 /* return only visible files */
2376 done = false;
2377 while (!done)
2378 {
2379 cipb.hFileInfo.ioDirID = dp->dir_id;
2380 /* directory ID found by opendir */
2381 cipb.hFileInfo.ioFDirIndex = dp->current_index;
7d0393cf 2382
1a578e9b
AC
2383 errno = PBGetCatInfo (&cipb, false);
2384 if (errno != noErr)
2385 {
2386 errno = ENOENT;
2387 return 0;
2388 }
7d0393cf
JB
2389
2390 /* insist on a visible entry */
1a578e9b
AC
2391 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* directory? */
2392 done = !(cipb.dirInfo.ioDrUsrWds.frFlags & fInvisible);
2393 else
2394 done = !(cipb.hFileInfo.ioFlFndrInfo.fdFlags & fInvisible);
7d0393cf 2395
1a578e9b
AC
2396 dp->current_index++;
2397 }
2398
2399 p2cstr (s_name);
7d0393cf 2400
1a578e9b
AC
2401 p = s_name;
2402 while (*p)
2403 {
2404 if (*p == '/')
2405 *p = ':';
2406 p++;
2407 }
2408
2409 s_dirent.d_ino = cipb.dirInfo.ioDrDirID;
2410 /* value unimportant: non-zero for valid file */
2411 s_dirent.d_name = s_name;
7d0393cf 2412
1a578e9b
AC
2413 return &s_dirent;
2414 }
2415}
2416
2417
2418char *
2419getwd (char *path)
2420{
2421 char mac_pathname[MAXPATHLEN+1];
2422 Str255 directory_name;
2423 OSErr errno;
2424 CInfoPBRec cipb;
2425
2426 if (path_from_vol_dir_name (mac_pathname, 255, 0, 0, "\p") == 0)
2427 return NULL;
2428
60fe1161 2429 if (mac_to_posix_pathname (mac_pathname, path, MAXPATHLEN+1) == 0)
1a578e9b
AC
2430 return 0;
2431 else
2432 return path;
2433}
2434
e0f712ba
AC
2435#endif /* ! MAC_OSX */
2436
1a578e9b
AC
2437
2438void
2439initialize_applescript ()
2440{
2441 AEDesc null_desc;
2442 OSAError osaerror;
7d0393cf 2443
1a578e9b
AC
2444 /* if open fails, as_scripting_component is set to NULL. Its
2445 subsequent use in OSA calls will fail with badComponentInstance
2446 error. */
2447 as_scripting_component = OpenDefaultComponent (kOSAComponentType,
2448 kAppleScriptSubtype);
2449
2450 null_desc.descriptorType = typeNull;
2451 null_desc.dataHandle = 0;
2452 osaerror = OSAMakeContext (as_scripting_component, &null_desc,
2453 kOSANullScript, &as_script_context);
2454 if (osaerror)
2455 as_script_context = kOSANullScript;
2456 /* use default context if create fails */
2457}
2458
2459
2460void terminate_applescript()
2461{
2462 OSADispose (as_scripting_component, as_script_context);
2463 CloseComponent (as_scripting_component);
2464}
2465
2466
2467/* Compile and execute the AppleScript SCRIPT and return the error
2468 status as function value. A zero is returned if compilation and
2469 execution is successful, in which case RESULT returns a pointer to
2470 a string containing the resulting script value. Otherwise, the Mac
2471 error code is returned and RESULT returns a pointer to an error
2472 string. In both cases the caller should deallocate the storage
2473 used by the string pointed to by RESULT if it is non-NULL. For
2474 documentation on the MacOS scripting architecture, see Inside
2475 Macintosh - Interapplication Communications: Scripting Components. */
2476
2477static long
2478do_applescript (char *script, char **result)
2479{
2480 AEDesc script_desc, result_desc, error_desc;
2481 OSErr error;
2482 OSAError osaerror;
2483 long length;
2484
2485 *result = 0;
2486
84c0c2cc
AC
2487 if (!as_scripting_component)
2488 initialize_applescript();
2489
1a578e9b
AC
2490 error = AECreateDesc (typeChar, script, strlen(script), &script_desc);
2491 if (error)
2492 return error;
2493
2494 osaerror = OSADoScript (as_scripting_component, &script_desc, kOSANullScript,
2495 typeChar, kOSAModeNull, &result_desc);
2496
2497 if (osaerror == errOSAScriptError)
2498 {
2499 /* error executing AppleScript: retrieve error message */
2500 if (!OSAScriptError (as_scripting_component, kOSAErrorMessage, typeChar,
2501 &error_desc))
2502 {
e0f712ba
AC
2503#if TARGET_API_MAC_CARBON
2504 length = AEGetDescDataSize (&error_desc);
2505 *result = (char *) xmalloc (length + 1);
2506 if (*result)
2507 {
2508 AEGetDescData (&error_desc, *result, length);
2509 *(*result + length) = '\0';
2510 }
2511#else /* not TARGET_API_MAC_CARBON */
1a578e9b
AC
2512 HLock (error_desc.dataHandle);
2513 length = GetHandleSize(error_desc.dataHandle);
2514 *result = (char *) xmalloc (length + 1);
2515 if (*result)
2516 {
2517 memcpy (*result, *(error_desc.dataHandle), length);
2518 *(*result + length) = '\0';
2519 }
2520 HUnlock (error_desc.dataHandle);
e0f712ba 2521#endif /* not TARGET_API_MAC_CARBON */
1a578e9b
AC
2522 AEDisposeDesc (&error_desc);
2523 }
2524 }
2525 else if (osaerror == noErr) /* success: retrieve resulting script value */
2526 {
e0f712ba
AC
2527#if TARGET_API_MAC_CARBON
2528 length = AEGetDescDataSize (&result_desc);
2529 *result = (char *) xmalloc (length + 1);
2530 if (*result)
2531 {
2532 AEGetDescData (&result_desc, *result, length);
2533 *(*result + length) = '\0';
2534 }
2535#else /* not TARGET_API_MAC_CARBON */
1a578e9b
AC
2536 HLock (result_desc.dataHandle);
2537 length = GetHandleSize(result_desc.dataHandle);
2538 *result = (char *) xmalloc (length + 1);
2539 if (*result)
2540 {
2541 memcpy (*result, *(result_desc.dataHandle), length);
2542 *(*result + length) = '\0';
2543 }
2544 HUnlock (result_desc.dataHandle);
e0f712ba 2545#endif /* not TARGET_API_MAC_CARBON */
84c0c2cc 2546 AEDisposeDesc (&result_desc);
1a578e9b
AC
2547 }
2548
2549 AEDisposeDesc (&script_desc);
1a578e9b
AC
2550
2551 return osaerror;
2552}
2553
2554
2555DEFUN ("do-applescript", Fdo_applescript, Sdo_applescript, 1, 1, 0,
e0f712ba
AC
2556 doc: /* Compile and execute AppleScript SCRIPT and retrieve and return the result.
2557If compilation and execution are successful, the resulting script
2558value is returned as a string. Otherwise the function aborts and
2559displays the error message returned by the AppleScript scripting
2560component. */)
1a578e9b
AC
2561 (script)
2562 Lisp_Object script;
2563{
2564 char *result, *temp;
2565 Lisp_Object lisp_result;
2566 long status;
2567
e0f712ba 2568 CHECK_STRING (script);
7d0393cf 2569
c3f4c690 2570 BLOCK_INPUT;
d5db4077 2571 status = do_applescript (SDATA (script), &result);
c3f4c690 2572 UNBLOCK_INPUT;
1a578e9b
AC
2573 if (status)
2574 {
2575 if (!result)
84c0c2cc 2576 error ("AppleScript error %d", status);
1a578e9b
AC
2577 else
2578 {
2579 /* Unfortunately only OSADoScript in do_applescript knows how
2580 how large the resulting script value or error message is
2581 going to be and therefore as caller memory must be
2582 deallocated here. It is necessary to free the error
2583 message before calling error to avoid a memory leak. */
2584 temp = (char *) alloca (strlen (result) + 1);
2585 strcpy (temp, result);
2586 xfree (result);
2587 error (temp);
2588 }
2589 }
2590 else
2591 {
2592 lisp_result = build_string (result);
2593 xfree (result);
2594 return lisp_result;
2595 }
2596}
2597
2598
e0f712ba
AC
2599DEFUN ("mac-file-name-to-posix", Fmac_file_name_to_posix,
2600 Smac_file_name_to_posix, 1, 1, 0,
2601 doc: /* Convert Macintosh filename to Posix form. */)
2602 (mac_filename)
2603 Lisp_Object mac_filename;
1a578e9b 2604{
60fe1161 2605 char posix_filename[MAXPATHLEN+1];
1a578e9b 2606
e0f712ba 2607 CHECK_STRING (mac_filename);
7d0393cf 2608
d5db4077 2609 if (mac_to_posix_pathname (SDATA (mac_filename), posix_filename,
1a578e9b 2610 MAXPATHLEN))
60fe1161 2611 return build_string (posix_filename);
1a578e9b
AC
2612 else
2613 return Qnil;
2614}
2615
2616
e0f712ba
AC
2617DEFUN ("posix-file-name-to-mac", Fposix_file_name_to_mac,
2618 Sposix_file_name_to_mac, 1, 1, 0,
2619 doc: /* Convert Posix filename to Mac form. */)
2620 (posix_filename)
2621 Lisp_Object posix_filename;
1a578e9b
AC
2622{
2623 char mac_filename[MAXPATHLEN+1];
2624
e0f712ba 2625 CHECK_STRING (posix_filename);
7d0393cf 2626
d5db4077 2627 if (posix_to_mac_pathname (SDATA (posix_filename), mac_filename,
1a578e9b
AC
2628 MAXPATHLEN))
2629 return build_string (mac_filename);
2630 else
2631 return Qnil;
2632}
2633
2634
2635/* set interprogram-paste-function to mac-paste-function in mac-win.el
2636 to enable Emacs to obtain the contents of the Mac clipboard. */
2637DEFUN ("mac-paste-function", Fmac_paste_function, Smac_paste_function, 0, 0, 0,
e0f712ba
AC
2638 doc: /* Return the contents of the Mac clipboard as a string. */)
2639 ()
1a578e9b 2640{
e0f712ba 2641#if TARGET_API_MAC_CARBON
c3f4c690 2642 OSStatus err;
e0f712ba
AC
2643 ScrapRef scrap;
2644 ScrapFlavorFlags sff;
2645 Size s;
2646 int i;
2647 char *data;
2648
c3f4c690
ST
2649 BLOCK_INPUT;
2650 err = GetCurrentScrap (&scrap);
2651 if (err == noErr)
2652 err = GetScrapFlavorFlags (scrap, kScrapFlavorTypeText, &sff);
2653 if (err == noErr)
2654 err = GetScrapFlavorSize (scrap, kScrapFlavorTypeText, &s);
2655 if (err == noErr && (data = (char*) alloca (s)))
2656 err = GetScrapFlavorData (scrap, kScrapFlavorTypeText, &s, data);
2657 UNBLOCK_INPUT;
2658 if (err != noErr || s == 0)
e0f712ba 2659 return Qnil;
7d0393cf 2660
e0f712ba
AC
2661 /* Emacs expects clipboard contents have Unix-style eol's */
2662 for (i = 0; i < s; i++)
2663 if (data[i] == '\r')
2664 data[i] = '\n';
2665
2666 return make_string (data, s);
2667#else /* not TARGET_API_MAC_CARBON */
1a578e9b
AC
2668 Lisp_Object value;
2669 Handle my_handle;
2670 long scrap_offset, rc, i;
2671
2672 my_handle = NewHandle (0); /* allocate 0-length data area */
2673
2674 rc = GetScrap (my_handle, 'TEXT', &scrap_offset);
2675 if (rc < 0)
2676 return Qnil;
2677
2678 HLock (my_handle);
2679
2680 /* Emacs expects clipboard contents have Unix-style eol's */
2681 for (i = 0; i < rc; i++)
2682 if ((*my_handle)[i] == '\r')
2683 (*my_handle)[i] = '\n';
2684
2685 value = make_string (*my_handle, rc);
2686
2687 HUnlock (my_handle);
7d0393cf 2688
1a578e9b
AC
2689 DisposeHandle (my_handle);
2690
2691 return value;
e0f712ba 2692#endif /* not TARGET_API_MAC_CARBON */
1a578e9b
AC
2693}
2694
2695
2696/* set interprogram-cut-function to mac-cut-function in mac-win.el
2697 to enable Emacs to write the top of the kill-ring to the Mac clipboard. */
2698DEFUN ("mac-cut-function", Fmac_cut_function, Smac_cut_function, 1, 2, 0,
e0f712ba 2699 doc: /* Put the value of the string parameter to the Mac clipboard. */)
1a578e9b
AC
2700 (value, push)
2701 Lisp_Object value, push;
2702{
2703 char *buf;
2704 int len, i;
2705
2706 /* fixme: ignore the push flag for now */
2707
e0f712ba 2708 CHECK_STRING (value);
7d0393cf 2709
d5db4077 2710 len = SCHARS (value);
e0f712ba 2711 buf = (char *) alloca (len+1);
d5db4077 2712 bcopy (SDATA (value), buf, len);
e0f712ba 2713 buf[len] = '\0';
7d0393cf 2714
1a578e9b
AC
2715 /* convert to Mac-style eol's before sending to clipboard */
2716 for (i = 0; i < len; i++)
2717 if (buf[i] == '\n')
2718 buf[i] = '\r';
2719
e0f712ba
AC
2720#if TARGET_API_MAC_CARBON
2721 {
2722 ScrapRef scrap;
c3f4c690
ST
2723
2724 BLOCK_INPUT;
e0f712ba
AC
2725 ClearCurrentScrap ();
2726 if (GetCurrentScrap (&scrap) != noErr)
c3f4c690
ST
2727 {
2728 UNBLOCK_INPUT;
2729 error ("cannot get current scrap");
2730 }
e0f712ba
AC
2731
2732 if (PutScrapFlavor (scrap, kScrapFlavorTypeText, kScrapFlavorMaskNone, len,
2733 buf) != noErr)
c3f4c690
ST
2734 {
2735 UNBLOCK_INPUT;
2736 error ("cannot put to scrap");
2737 }
2738 UNBLOCK_INPUT;
e0f712ba
AC
2739 }
2740#else /* not TARGET_API_MAC_CARBON */
1a578e9b
AC
2741 ZeroScrap ();
2742 PutScrap (len, 'TEXT', buf);
e0f712ba 2743#endif /* not TARGET_API_MAC_CARBON */
7d0393cf 2744
1a578e9b
AC
2745 return Qnil;
2746}
2747
2748
2749DEFUN ("x-selection-exists-p", Fx_selection_exists_p, Sx_selection_exists_p,
e0f712ba
AC
2750 0, 1, 0,
2751 doc: /* Whether there is an owner for the given X Selection.
2752The arg should be the name of the selection in question, typically one of
2753the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.
14bda6db 2754\(Those are literal upper-case symbol names, since that's what X expects.)
e0f712ba
AC
2755For convenience, the symbol nil is the same as `PRIMARY',
2756and t is the same as `SECONDARY'. */)
1a578e9b
AC
2757 (selection)
2758 Lisp_Object selection;
2759{
e0f712ba 2760 CHECK_SYMBOL (selection);
1a578e9b
AC
2761
2762 /* Return nil for PRIMARY and SECONDARY selections; for CLIPBOARD, check
2763 if the clipboard currently has valid text format contents. */
2764
2765 if (EQ (selection, QCLIPBOARD))
2766 {
2767 Lisp_Object val = Qnil;
e0f712ba
AC
2768
2769#if TARGET_API_MAC_CARBON
2770 ScrapRef scrap;
2771 ScrapFlavorFlags sff;
2772
c3f4c690 2773 BLOCK_INPUT;
e0f712ba
AC
2774 if (GetCurrentScrap (&scrap) == noErr)
2775 if (GetScrapFlavorFlags (scrap, kScrapFlavorTypeText, &sff) == noErr)
2776 val = Qt;
c3f4c690 2777 UNBLOCK_INPUT;
e0f712ba 2778#else /* not TARGET_API_MAC_CARBON */
1a578e9b
AC
2779 Handle my_handle;
2780 long rc, scrap_offset;
2781
2782 my_handle = NewHandle (0);
2783
2784 rc = GetScrap (my_handle, 'TEXT', &scrap_offset);
2785 if (rc >= 0)
2786 val = Qt;
2787
2788 DisposeHandle (my_handle);
e0f712ba 2789#endif /* not TARGET_API_MAC_CARBON */
1a578e9b
AC
2790
2791 return val;
2792 }
2793 return Qnil;
2794}
2795
8030369c
AC
2796#ifdef MAC_OSX
2797#undef select
2798
2799extern int inhibit_window_system;
2b187eac 2800extern int noninteractive;
8030369c
AC
2801
2802/* When Emacs is started from the Finder, SELECT always immediately
2803 returns as if input is present when file descriptor 0 is polled for
2804 input. Strangely, when Emacs is run as a GUI application from the
2805 command line, it blocks in the same situation. This `wrapper' of
2806 the system call SELECT corrects this discrepancy. */
2807int
2808sys_select (n, rfds, wfds, efds, timeout)
bfcf6608
ST
2809 int n;
2810 SELECT_TYPE *rfds;
2811 SELECT_TYPE *wfds;
2812 SELECT_TYPE *efds;
2813 struct timeval *timeout;
8030369c 2814{
bfcf6608
ST
2815 OSErr err;
2816 EMACS_TIME end_time, now, remaining_time;
2817
e082ac9d
ST
2818 if (inhibit_window_system || noninteractive
2819 || rfds == NULL || !FD_ISSET (0, rfds))
bfcf6608
ST
2820 return select (n, rfds, wfds, efds, timeout);
2821
2822 if (wfds == NULL && efds == NULL)
2b187eac 2823 {
bfcf6608
ST
2824 int i;
2825
2826 for (i = 1; i < n; i++)
2827 if (FD_ISSET (i, rfds))
2828 break;
2829 if (i == n)
2830 {
2831 EventTimeout timeout_sec =
2832 (timeout
2833 ? (EMACS_SECS (*timeout) * kEventDurationSecond
2834 + EMACS_USECS (*timeout) * kEventDurationMicrosecond)
2835 : kEventDurationForever);
2836
2837 BLOCK_INPUT;
2838 err = ReceiveNextEvent (0, NULL, timeout_sec,
2839 kEventLeaveInQueue, NULL);
2840 UNBLOCK_INPUT;
2841 if (err == noErr)
96720f09 2842 {
e082ac9d
ST
2843 FD_ZERO (rfds);
2844 FD_SET (0, rfds);
2845 return 1;
96720f09 2846 }
bfcf6608
ST
2847 else
2848 return 0;
2b187eac 2849 }
2b187eac 2850 }
2b187eac 2851
bfcf6608 2852 if (timeout)
2b187eac 2853 {
bfcf6608
ST
2854 remaining_time = *timeout;
2855 EMACS_GET_TIME (now);
2856 EMACS_ADD_TIME (end_time, now, remaining_time);
2b187eac 2857 }
bfcf6608
ST
2858 FD_CLR (0, rfds);
2859 do
2860 {
2861 EMACS_TIME select_timeout;
2862 SELECT_TYPE orfds = *rfds;
2863 int r;
177c0ea7 2864
bfcf6608
ST
2865 EMACS_SET_SECS_USECS (select_timeout, 0, 20000);
2866
2867 if (timeout && EMACS_TIME_LT (remaining_time, select_timeout))
2868 select_timeout = remaining_time;
2869
2870 r = select (n, &orfds, wfds, efds, &select_timeout);
2871 BLOCK_INPUT;
2872 err = ReceiveNextEvent (0, NULL, kEventDurationNoWait,
2873 kEventLeaveInQueue, NULL);
2874 UNBLOCK_INPUT;
2875 if (r > 0)
2876 {
2877 *rfds = orfds;
2878 if (err == noErr)
2879 {
2880 FD_SET (0, rfds);
2881 r++;
2882 }
2883 return r;
2884 }
2885 else if (err == noErr)
2886 {
2887 FD_ZERO (rfds);
2888 FD_SET (0, rfds);
2889 return 1;
2890 }
1000788b 2891
bfcf6608
ST
2892 if (timeout)
2893 {
2894 EMACS_GET_TIME (now);
2895 EMACS_SUB_TIME (remaining_time, end_time, now);
2896 }
2897 }
2898 while (!timeout || EMACS_TIME_LT (now, end_time));
2899
2900 return 0;
2901}
1000788b
AC
2902
2903/* Set up environment variables so that Emacs can correctly find its
2904 support files when packaged as an application bundle. Directories
2905 placed in /usr/local/share/emacs/<emacs-version>/, /usr/local/bin,
2906 and /usr/local/libexec/emacs/<emacs-version>/<system-configuration>
2907 by `make install' by default can instead be placed in
2908 .../Emacs.app/Contents/Resources/ and
2909 .../Emacs.app/Contents/MacOS/. Each of these environment variables
2910 is changed only if it is not already set. Presumably if the user
2911 sets an environment variable, he will want to use files in his path
2912 instead of ones in the application bundle. */
2913void
2914init_mac_osx_environment ()
2915{
2916 CFBundleRef bundle;
2917 CFURLRef bundleURL;
2918 CFStringRef cf_app_bundle_pathname;
2919 int app_bundle_pathname_len;
2920 char *app_bundle_pathname;
2921 char *p, *q;
2922 struct stat st;
2923
2924 /* Fetch the pathname of the application bundle as a C string into
2925 app_bundle_pathname. */
2926
2927 bundle = CFBundleGetMainBundle ();
2928 if (!bundle)
2929 return;
2930
2931 bundleURL = CFBundleCopyBundleURL (bundle);
2932 if (!bundleURL)
2933 return;
2934
2935 cf_app_bundle_pathname = CFURLCopyFileSystemPath (bundleURL,
2936 kCFURLPOSIXPathStyle);
2937 app_bundle_pathname_len = CFStringGetLength (cf_app_bundle_pathname);
2938 app_bundle_pathname = (char *) alloca (app_bundle_pathname_len + 1);
2939
2940 if (!CFStringGetCString (cf_app_bundle_pathname,
2941 app_bundle_pathname,
2942 app_bundle_pathname_len + 1,
2943 kCFStringEncodingISOLatin1))
2944 {
2945 CFRelease (cf_app_bundle_pathname);
2946 return;
2947 }
2948
2949 CFRelease (cf_app_bundle_pathname);
2950
2951 /* P should have sufficient room for the pathname of the bundle plus
2952 the subpath in it leading to the respective directories. Q
2953 should have three times that much room because EMACSLOADPATH can
2954 have the value "<path to lisp dir>:<path to leim dir>:<path to
2955 site-lisp dir>". */
2956 p = (char *) alloca (app_bundle_pathname_len + 50);
2957 q = (char *) alloca (3 * app_bundle_pathname_len + 150);
2958 if (!getenv ("EMACSLOADPATH"))
2959 {
2960 q[0] = '\0';
2961
2962 strcpy (p, app_bundle_pathname);
2963 strcat (p, "/Contents/Resources/lisp");
2964 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
2965 strcat (q, p);
2966
2967 strcpy (p, app_bundle_pathname);
2968 strcat (p, "/Contents/Resources/leim");
2969 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
2970 {
2971 if (q[0] != '\0')
2972 strcat (q, ":");
2973 strcat (q, p);
2974 }
2975
2976 strcpy (p, app_bundle_pathname);
2977 strcat (p, "/Contents/Resources/site-lisp");
2978 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
2979 {
2980 if (q[0] != '\0')
2981 strcat (q, ":");
2982 strcat (q, p);
2983 }
2984
2985 if (q[0] != '\0')
2986 setenv ("EMACSLOADPATH", q, 1);
2987 }
2988
2989 if (!getenv ("EMACSPATH"))
2990 {
2991 q[0] = '\0';
2992
2993 strcpy (p, app_bundle_pathname);
e8f25745 2994 strcat (p, "/Contents/MacOS/libexec");
1000788b
AC
2995 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
2996 strcat (q, p);
2997
2998 strcpy (p, app_bundle_pathname);
e8f25745 2999 strcat (p, "/Contents/MacOS/bin");
1000788b
AC
3000 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
3001 {
3002 if (q[0] != '\0')
3003 strcat (q, ":");
3004 strcat (q, p);
3005 }
3006
3007 if (q[0] != '\0')
3008 setenv ("EMACSPATH", q, 1);
3009 }
3010
3011 if (!getenv ("EMACSDATA"))
3012 {
3013 strcpy (p, app_bundle_pathname);
3014 strcat (p, "/Contents/Resources/etc");
3015 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
3016 setenv ("EMACSDATA", p, 1);
3017 }
3018
3019 if (!getenv ("EMACSDOC"))
3020 {
3021 strcpy (p, app_bundle_pathname);
3022 strcat (p, "/Contents/Resources/etc");
3023 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
3024 setenv ("EMACSDOC", p, 1);
3025 }
3026
3027 if (!getenv ("INFOPATH"))
3028 {
3029 strcpy (p, app_bundle_pathname);
3030 strcat (p, "/Contents/Resources/info");
3031 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
3032 setenv ("INFOPATH", p, 1);
3033 }
3034}
8030369c 3035#endif /* MAC_OSX */
1a578e9b
AC
3036
3037void
3038syms_of_mac ()
3039{
3040 QCLIPBOARD = intern ("CLIPBOARD");
3041 staticpro (&QCLIPBOARD);
7d0393cf 3042
1a578e9b
AC
3043 defsubr (&Smac_paste_function);
3044 defsubr (&Smac_cut_function);
3045 defsubr (&Sx_selection_exists_p);
3046
3047 defsubr (&Sdo_applescript);
60fe1161
AC
3048 defsubr (&Smac_file_name_to_posix);
3049 defsubr (&Sposix_file_name_to_mac);
1a578e9b 3050}
ab5796a9
MB
3051
3052/* arch-tag: 29d30c1f-0c6b-4f88-8a6d-0558d7f9dbff
3053 (do not change this comment) */