]> code.delx.au - gnu-emacs/blob - src/mac.c
*** empty log message ***
[gnu-emacs] / src / mac.c
1 /* Unix emulation routines for GNU Emacs on the Mac OS.
2 Copyright (C) 2000, 2001 Free Software Foundation, Inc.
3
4 This file is part of GNU Emacs.
5
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
20
21 /* Contributed by Andrew Choi (akochoi@mac.com). */
22
23 #include <config.h>
24
25 #include <stdio.h>
26 #include <errno.h>
27 #include <time.h>
28 #include <utime.h>
29 #include <dirent.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <string.h>
33 #include <pwd.h>
34 #include <grp.h>
35 #include <sys/param.h>
36 #include <stdlib.h>
37 #include <fcntl.h>
38 #if __MWERKS__
39 #include <unistd.h>
40 #endif
41
42 #ifdef MAC_OSX
43 #undef mktime
44 #undef DEBUG
45 #undef free
46 #undef malloc
47 #undef realloc
48 #undef init_process
49 #include <Carbon/Carbon.h>
50 #undef mktime
51 #define mktime emacs_mktime
52 #undef free
53 #define free unexec_free
54 #undef malloc
55 #define malloc unexec_malloc
56 #undef realloc
57 #define realloc unexec_realloc
58 #undef init_process
59 #define init_process emacs_init_process
60 #else /* not MAC_OSX */
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>
71 #include <Scrap.h>
72 #endif /* not MAC_OSX */
73
74 #include "lisp.h"
75 #include "process.h"
76 #include "sysselect.h"
77 #include "systime.h"
78 #include "blockinput.h"
79
80 Lisp_Object QCLIPBOARD;
81
82 /* An instance of the AppleScript component. */
83 static ComponentInstance as_scripting_component;
84 /* The single script context used for all script executions. */
85 static 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
93 void
94 string_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;
100
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
111 /* Convert a Mac pathname to Posix form. A Mac full pathname is one
112 that does not begin with a ':' and contains at least one ':'. A Mac
113 full pathname causes a '/' to be prepended to the Posix pathname.
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,
117 otherwise, insert a "../" into the Posix pathname.
118 Returns 1 if successful; 0 if fails. */
119
120 int
121 mac_to_posix_pathname (const char *mfn, char *ufn, int ufnbuflen)
122 {
123 const char *p, *q, *pe;
124
125 strcpy (ufn, "");
126
127 if (*mfn == '\0')
128 return 1;
129
130 p = strchr (mfn, ':');
131 if (p != 0 && p != mfn) /* full pathname */
132 strcat (ufn, "/");
133
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 }
168
169 return 1;
170 }
171
172
173 extern char *get_temp_dir_name ();
174
175
176 /* Convert a Posix pathname to Mac form. Approximately reverse of the
177 above in algorithm. */
178
179 int
180 posix_to_mac_pathname (const char *ufn, char *mfn, int mfnbuflen)
181 {
182 const char *p, *q, *pe;
183 char expanded_pathname[MAXPATHLEN+1];
184
185 strcpy (mfn, "");
186
187 if (*ufn == '\0')
188 return 1;
189
190 p = ufn;
191
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 */
225 }
226 else if (*p != '/') /* relative pathname */
227 strcat (mfn, ":");
228
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 }
261
262 return 1;
263 }
264
265 #if TARGET_API_MAC_CARBON
266 CFStringRef
267 cfstring_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
281 #ifndef MAC_OSX
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__
297 #if __MSL__ < 0x6000
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)
302 #else /* __MSL__ >= 0x6000 */
303 /* CW changes Pro 6 to follow Unix! */
304 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
305 #endif /* __MSL__ >= 0x6000 */
306 #elif __MRC__
307 /* MPW library functions follow Unix (confused?). */
308 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
309 #else /* not __MRC__ */
310 You lose!!!
311 #endif /* not __MRC__ */
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
321 int
322 stat_noalias (const char *path, struct stat *buf)
323 {
324 char mac_pathname[MAXPATHLEN+1];
325 CInfoPBRec cipb;
326
327 if (posix_to_mac_pathname (path, mac_pathname, MAXPATHLEN+1) == 0)
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 */
336
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;
346
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 */
377 buf->st_mode &= ~S_IFREG;
378 buf->st_mode |= S_IFLNK;
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
390 int
391 lstat (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;
402
403 return stat_noalias (true_pathname, buf);
404 }
405
406
407 int
408 stat (const char *path, struct stat *sb)
409 {
410 int result;
411 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
412 int len;
413
414 if ((result = stat_noalias (path, sb)) >= 0 &&
415 ! (sb->st_mode & S_IFLNK))
416 return result;
417
418 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
419 return -1;
420
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
444 int
445 fstat (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
455 int
456 mkdir (const char *dirname, int mode)
457 {
458 #pragma unused(mode)
459
460 HFileParam hfpb;
461 char true_pathname[MAXPATHLEN+1], mac_pathname[MAXPATHLEN+1];
462
463 if (find_true_pathname (dirname, true_pathname, MAXPATHLEN+1) == -1)
464 return -1;
465
466 if (posix_to_mac_pathname (true_pathname, mac_pathname, MAXPATHLEN+1) == 0)
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 */
473
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
481 sys_rmdir (const char *dirname)
482 {
483 HFileParam hfpb;
484 char mac_pathname[MAXPATHLEN+1];
485
486 if (posix_to_mac_pathname (dirname, mac_pathname, MAXPATHLEN+1) == 0)
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 */
493
494 errno = PBHDelete ((HParmBlkPtr) &hfpb, false);
495 return errno == noErr ? 0 : -1;
496 }
497
498
499 #ifdef __MRC__
500 /* No implementation yet. */
501 int
502 execvp (const char *path, ...)
503 {
504 return -1;
505 }
506 #endif /* __MRC__ */
507
508
509 int
510 utime (const char *path, const struct utimbuf *times)
511 {
512 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
513 int len;
514 char mac_pathname[MAXPATHLEN+1];
515 CInfoPBRec cipb;
516
517 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
518 return -1;
519
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
526 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
527 return -1;
528
529 c2pstr (mac_pathname);
530 cipb.hFileInfo.ioNamePtr = mac_pathname;
531 cipb.hFileInfo.ioVRefNum = 0;
532 cipb.hFileInfo.ioDirID = 0;
533 cipb.hFileInfo.ioFDirIndex = 0;
534 /* set to 0 to get information about specific dir or file */
535
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 */
571 int
572 access (const char *path, int mode)
573 {
574 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
575 int len;
576 char mac_pathname[MAXPATHLEN+1];
577 CInfoPBRec cipb;
578
579 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
580 return -1;
581
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
588 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
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 */
597
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
627 int
628 sys_open (const char *path, int oflag)
629 {
630 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
631 int len;
632 char mac_pathname[MAXPATHLEN+1];
633
634 if (strcmp (path, "/dev/null") == 0)
635 return DEV_NULL_FD; /* some bogus fd to be ignored in write */
636
637 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
638 return -1;
639
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
646 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
647 return -1;
648 else
649 {
650 #ifdef __MRC__
651 int res = open (mac_pathname, oflag);
652 /* if (oflag == O_WRONLY || oflag == O_RDWR) */
653 if (oflag & O_CREAT)
654 fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
655 return res;
656 #else /* not __MRC__ */
657 return open (mac_pathname, oflag);
658 #endif /* not __MRC__ */
659 }
660 }
661
662
663 #undef creat
664 int
665 sys_creat (const char *path, mode_t mode)
666 {
667 char true_pathname[MAXPATHLEN+1];
668 int len;
669 char mac_pathname[MAXPATHLEN+1];
670
671 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
672 return -1;
673
674 if (!posix_to_mac_pathname (true_pathname, mac_pathname, MAXPATHLEN+1))
675 return -1;
676 else
677 {
678 #ifdef __MRC__
679 int result = creat (mac_pathname);
680 fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
681 return result;
682 #else /* not __MRC__ */
683 return creat (mac_pathname, mode);
684 #endif /* not __MRC__ */
685 }
686 }
687
688
689 #undef unlink
690 int
691 sys_unlink (const char *path)
692 {
693 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
694 int len;
695 char mac_pathname[MAXPATHLEN+1];
696
697 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
698 return -1;
699
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
706 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
707 return -1;
708 else
709 return unlink (mac_pathname);
710 }
711
712
713 #undef read
714 int
715 sys_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
720 #if __MSL__ >= 0x6000
721 return _read (fildes, buf, count);
722 #else
723 return read (fildes, buf, count);
724 #endif
725 }
726
727
728 #undef write
729 int
730 sys_write (int fildes, const char *buf, int count)
731 {
732 if (fildes == DEV_NULL_FD)
733 return count;
734 else
735 #if __MSL__ >= 0x6000
736 return _write (fildes, buf, count);
737 #else
738 return write (fildes, buf, count);
739 #endif
740 }
741
742
743 #undef rename
744 int
745 sys_rename (const char * old_name, const char * new_name)
746 {
747 char true_old_pathname[MAXPATHLEN+1], true_new_pathname[MAXPATHLEN+1];
748 char fully_resolved_old_name[MAXPATHLEN+1];
749 int len;
750 char mac_old_name[MAXPATHLEN+1], mac_new_name[MAXPATHLEN+1];
751
752 if (find_true_pathname (old_name, true_old_pathname, MAXPATHLEN+1) == -1)
753 return -1;
754
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;
763
764 if (strcmp (fully_resolved_old_name, true_new_pathname) == 0)
765 return 0;
766
767 if (!posix_to_mac_pathname (fully_resolved_old_name,
768 mac_old_name,
769 MAXPATHLEN+1))
770 return -1;
771
772 if (!posix_to_mac_pathname(true_new_pathname, mac_new_name, MAXPATHLEN+1))
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);
779
780 return rename (mac_old_name, mac_new_name);
781 }
782
783
784 #undef fopen
785 extern FILE *fopen (const char *name, const char *mode);
786 FILE *
787 sys_fopen (const char *name, const char *mode)
788 {
789 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
790 int len;
791 char mac_pathname[MAXPATHLEN+1];
792
793 if (find_true_pathname (name, true_pathname, MAXPATHLEN+1) == -1)
794 return 0;
795
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
802 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
803 return 0;
804 else
805 {
806 #ifdef __MRC__
807 if (mode[0] == 'w' || mode[0] == 'a')
808 fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
809 #endif /* not __MRC__ */
810 return fopen (mac_pathname, mode);
811 }
812 }
813
814
815 #include <Events.h>
816
817 long 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;
823 #else /* not __MRC__ and not __MWERKS__ */
824 You lose!!!
825 #endif /* not __MRC__ and not __MWERKS__ */
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
836 void
837 check_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
848 extern Boolean mac_wait_next_event (EventRecord *, UInt32, Boolean);
849
850 int
851 select (n, rfds, wfds, efds, timeout)
852 int n;
853 SELECT_TYPE *rfds;
854 SELECT_TYPE *wfds;
855 SELECT_TYPE *efds;
856 struct timeval *timeout;
857 {
858 #if TARGET_API_MAC_CARBON
859 return 1;
860 #else /* not TARGET_API_MAC_CARBON */
861 EventRecord e;
862 UInt32 sleep_time = EMACS_SECS (*timeout) * 60 +
863 ((EMACS_USECS (*timeout) * 60) / 1000000);
864
865 /* Can only handle wait for keyboard input. */
866 if (n > 1 || wfds || efds)
867 return -1;
868
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;
876
877 return 0;
878 #endif /* not TARGET_API_MAC_CARBON */
879 }
880
881
882 /* Called in sys_select to wait for an alarm signal to arrive. */
883
884 int
885 pause ()
886 {
887 EventRecord e;
888 unsigned long tick;
889
890 if (!target_ticks) /* no alarm pending */
891 return -1;
892
893 if ((tick = TickCount ()) < target_ticks)
894 WaitNextEvent (0, &e, target_ticks - tick, NULL); /* Accept no event;
895 just wait. by T.I. */
896
897 target_ticks = 0;
898 if (alarm_signal_func)
899 (*alarm_signal_func)(SIGALRM);
900
901 return 0;
902 }
903
904
905 int
906 alarm (int seconds)
907 {
908 long remaining = target_ticks ? (TickCount () - target_ticks) / 60 : 0;
909
910 target_ticks = seconds ? TickCount () + 60 * seconds : 0;
911
912 return (remaining < 0) ? 0 : (unsigned int) remaining;
913 }
914
915
916 #undef signal
917 #ifdef __MRC__
918 extern __sigfun signal (int signal, __sigfun signal_func);
919 __sigfun
920 sys_signal (int signal_num, __sigfun signal_func)
921 #elif __MWERKS__
922 extern __signal_func_ptr signal (int signal, __signal_func_ptr signal_func);
923 __signal_func_ptr
924 sys_signal (int signal_num, __signal_func_ptr signal_func)
925 #else /* not __MRC__ and not __MWERKS__ */
926 You lose!!!
927 #endif /* not __MRC__ and not __MWERKS__ */
928 {
929 if (signal_num != SIGALRM)
930 return signal (signal_num, signal_func);
931 else
932 {
933 #ifdef __MRC__
934 __sigfun old_signal_func;
935 #elif __MWERKS__
936 __signal_func_ptr old_signal_func;
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
953 int
954 gettimeofday (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);
981
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__
994 unsigned int
995 sleep (unsigned int seconds)
996 {
997 unsigned long time_up;
998 EventRecord e;
999
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 }
1006
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
1016 extern struct tm *gmtime (const time_t *);
1017 struct tm *
1018 sys_gmtime (const time_t *timer)
1019 {
1020 time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
1021
1022 return gmtime (&unix_time);
1023 }
1024
1025
1026 #undef localtime
1027 extern struct tm *localtime (const time_t *);
1028 struct tm *
1029 sys_localtime (const time_t *timer)
1030 {
1031 #if __MSL__ >= 0x6000
1032 time_t unix_time = *timer;
1033 #else
1034 time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
1035 #endif
1036
1037 return localtime (&unix_time);
1038 }
1039
1040
1041 #undef ctime
1042 extern char *ctime (const time_t *);
1043 char *
1044 sys_ctime (const time_t *timer)
1045 {
1046 #if __MSL__ >= 0x6000
1047 time_t unix_time = *timer;
1048 #else
1049 time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
1050 #endif
1051
1052 return ctime (&unix_time);
1053 }
1054
1055
1056 #undef time
1057 extern time_t time (time_t *);
1058 time_t
1059 sys_time (time_t *timer)
1060 {
1061 #if __MSL__ >= 0x6000
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;
1069
1070 return mac_time;
1071 }
1072
1073
1074 /* MPW strftime broken for "%p" format */
1075 #ifdef __MRC__
1076 #undef strftime
1077 #include <time.h>
1078 size_t
1079 sys_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
1105 int
1106 wait (int pid)
1107 {
1108 return 0;
1109 }
1110
1111
1112 void
1113 croak (char *badfunc)
1114 {
1115 printf ("%s not yet implemented\r\n", badfunc);
1116 exit (1);
1117 }
1118
1119
1120 char *
1121 index (const char * str, int chr)
1122 {
1123 return strchr (str, chr);
1124 }
1125
1126
1127 char *
1128 mktemp (char *template)
1129 {
1130 int len, k;
1131 static seqnum = 0;
1132
1133 len = strlen (template);
1134 k = len - 1;
1135 while (k >= 0 && template[k] == 'X')
1136 k--;
1137
1138 k++; /* make k index of first 'X' */
1139
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++);
1144
1145 return template;
1146 }
1147 else
1148 return 0;
1149 }
1150
1151
1152 /* Emulate getpwuid, getpwnam and others. */
1153
1154 #define PASSWD_FIELD_SIZE 256
1155
1156 static char my_passwd_name[PASSWD_FIELD_SIZE];
1157 static char my_passwd_dir[MAXPATHLEN+1];
1158
1159 static struct passwd my_passwd =
1160 {
1161 my_passwd_name,
1162 my_passwd_dir,
1163 };
1164
1165 static 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
1172
1173 /* Initialized by main () in macterm.c to pathname of emacs directory. */
1174
1175 char emacs_passwd_dir[MAXPATHLEN+1];
1176
1177 char *
1178 getwd (char *);
1179
1180 void
1181 init_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 }
1210
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
1221 static struct passwd emacs_passwd =
1222 {
1223 "emacs",
1224 emacs_passwd_dir,
1225 };
1226
1227 static int my_passwd_inited = 0;
1228
1229
1230 static void
1231 init_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
1253 struct passwd *
1254 getpwuid (uid_t uid)
1255 {
1256 if (!my_passwd_inited)
1257 {
1258 init_my_passwd ();
1259 my_passwd_inited = 1;
1260 }
1261
1262 return &my_passwd;
1263 }
1264
1265
1266 struct group *
1267 getgrgid (gid_t gid)
1268 {
1269 return &my_group;
1270 }
1271
1272
1273 struct passwd *
1274 getpwnam (const char *name)
1275 {
1276 if (strcmp (name, "emacs") == 0)
1277 return &emacs_passwd;
1278
1279 if (!my_passwd_inited)
1280 {
1281 init_my_passwd ();
1282 my_passwd_inited = 1;
1283 }
1284
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
1294 int
1295 fork ()
1296 {
1297 return -1;
1298 }
1299
1300
1301 int
1302 kill (int x, int y)
1303 {
1304 return -1;
1305 }
1306
1307
1308 void
1309 sys_subshell ()
1310 {
1311 error ("Can't spawn subshell");
1312 }
1313
1314
1315 int
1316 sigsetmask (int x)
1317 {
1318 return 0;
1319 }
1320
1321
1322 int
1323 sigblock (int mask)
1324 {
1325 return 0;
1326 }
1327
1328
1329 void
1330 request_sigio (void)
1331 {
1332 }
1333
1334
1335 void
1336 unrequest_sigio (void)
1337 {
1338 }
1339
1340
1341 int
1342 setpgrp ()
1343 {
1344 return 0;
1345 }
1346
1347
1348 /* No pipes yet. */
1349
1350 int
1351 pipe (int _fildes[2])
1352 {
1353 errno = EACCES;
1354 return -1;
1355 }
1356
1357
1358 /* Hard and symbolic links. */
1359
1360 int
1361 symlink (const char *name1, const char *name2)
1362 {
1363 errno = ENOENT;
1364 return -1;
1365 }
1366
1367
1368 int
1369 link (const char *name1, const char *name2)
1370 {
1371 errno = ENOENT;
1372 return -1;
1373 }
1374
1375 #endif /* ! MAC_OSX */
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. */
1380 int
1381 path_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;
1408
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 */
1420
1421 return 1; /* success */
1422 }
1423
1424 #ifndef MAC_OSX
1425
1426 int
1427 readlink (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
1436 if (posix_to_mac_pathname (path, mac_sym_link_name, MAXPATHLEN+1) == 0)
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
1461 if (mac_to_posix_pathname (mac_pathname, buf, bufsiz) == 0)
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
1473 static int
1474 find_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';
1484
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 }
1508
1509 if (len + strlen (p) + 1 >= bufsiz)
1510 return -1;
1511
1512 strcat (buf, p);
1513 return len + strlen (p);
1514 }
1515
1516
1517 mode_t
1518 umask (mode_t numask)
1519 {
1520 static mode_t mask = 022;
1521 mode_t oldmask = mask;
1522 mask = numask;
1523 return oldmask;
1524 }
1525
1526
1527 int
1528 chmod (const char *path, mode_t mode)
1529 {
1530 /* say it always succeed for now */
1531 return 0;
1532 }
1533
1534
1535 int
1536 dup (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
1545 You 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
1555 int
1556 dup2 (int oldd, int newd)
1557 {
1558 int fd, ret;
1559
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
1575 char *
1576 sbrk (int incr)
1577 {
1578 return (char *) -1;
1579 }
1580
1581
1582 int
1583 fsync (int fd)
1584 {
1585 return 0;
1586 }
1587
1588
1589 int
1590 ioctl (int d, int request, void *argp)
1591 {
1592 return -1;
1593 }
1594
1595
1596 #ifdef __MRC__
1597 int
1598 isatty (int fildes)
1599 {
1600 if (fildes >=0 && fildes <= 2)
1601 return 1;
1602 else
1603 return 0;
1604 }
1605
1606
1607 int
1608 getgid ()
1609 {
1610 return 100;
1611 }
1612
1613
1614 int
1615 getegid ()
1616 {
1617 return 100;
1618 }
1619
1620
1621 int
1622 getuid ()
1623 {
1624 return 200;
1625 }
1626
1627
1628 int
1629 geteuid ()
1630 {
1631 return 200;
1632 }
1633 #endif /* __MRC__ */
1634
1635
1636 #ifdef __MWERKS__
1637 #if __MSL__ < 0x6000
1638 #undef getpid
1639 int
1640 getpid ()
1641 {
1642 return 9999;
1643 }
1644 #endif
1645 #endif /* __MWERKS__ */
1646
1647 #endif /* ! MAC_OSX */
1648
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
1659 char *
1660 get_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;
1670
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;
1679
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:");
1685 else
1686 return NULL;
1687
1688 if (!mac_to_posix_pathname (full_path, unix_dir_name, MAXPATHLEN+1))
1689 return NULL;
1690
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
1704 #ifndef MAC_OSX
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
1709 contains numString strings, a pointer array with numString+1
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
1716 void
1717 get_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
1753 static char *
1754 get_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;
1763
1764 err = FindFolder (kOnSystemDisk, kSystemFolderType, kDontCreateFolder,
1765 &vol_ref_num, &dir_id);
1766 if (err != noErr)
1767 return NULL;
1768
1769 if (!path_from_vol_dir_name (full_path, 255, vol_ref_num, dir_id, "\p"))
1770 return NULL;
1771
1772 if (!mac_to_posix_pathname (full_path, system_folder_unix_name,
1773 MAXPATHLEN+1))
1774 return NULL;
1775
1776 return system_folder_unix_name;
1777 }
1778
1779
1780 char **environ;
1781
1782 #define ENVIRON_STRING_LIST_ID 128
1783
1784 /* Get environment variable definitions from STR# resource. */
1785
1786 void
1787 init_environ ()
1788 {
1789 int i;
1790
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
1838 char *
1839 getenv (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 */
1857 char *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__
1869 char *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 };
1879 #else /* not __MRC__ and not __MWERKS__ */
1880 You lose!!!
1881 #endif /* not __MRC__ and not __MWERKS__ */
1882
1883
1884 #include <utsname.h>
1885
1886 int
1887 uname (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. */
1906 const OSType kEmacsSubprocessSend = 'ESND';
1907
1908 /* Event class of HLE sent back from subprocess. */
1909 const OSType kEmacsSubprocessReply = 'ERPY';
1910
1911
1912 char *
1913 mystrchr (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
1932 char *
1933 mystrtok (char *s)
1934 {
1935 while (*s)
1936 s++;
1937
1938 return s + 1;
1939 }
1940
1941
1942 void
1943 mystrcpy (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
1970 int
1971 run_mac_command (argv, workdir, infn, outfn, errfn)
1972 unsigned char **argv;
1973 const char *workdir;
1974 const char *infn, *outfn, *errfn;
1975 {
1976 #if TARGET_API_MAC_CARBON
1977 return -1;
1978 #else /* not TARGET_API_MAC_CARBON */
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;
1990
1991 if (posix_to_mac_pathname (workdir, macworkdir, MAXPATHLEN+1) == 0)
1992 return -1;
1993 if (posix_to_mac_pathname (infn, macinfn, MAXPATHLEN+1) == 0)
1994 return -1;
1995 if (posix_to_mac_pathname (outfn, macoutfn, MAXPATHLEN+1) == 0)
1996 return -1;
1997 if (posix_to_mac_pathname (errfn, macerrfn, MAXPATHLEN+1) == 0)
1998 return -1;
1999
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];
2018
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, " ");
2025
2026 t = command;
2027 newargc = 0;
2028 t = mystrchr (t, ' ');
2029 while (t)
2030 {
2031 newargc++;
2032 t = mystrchr (t+1, ' ');
2033 }
2034
2035 newargv = (char **) alloca (sizeof (char *) * newargc);
2036
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 }
2046
2047 if (strncmp (newargv[0], "~emacs/", 7) == 0)
2048 {
2049 if (posix_to_mac_pathname (newargv[0], tempmacpathname, MAXPATHLEN+1)
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]);
2059 #endif /* 0 */
2060 Lisp_Object path;
2061 openp (Vexec_path, build_string (newargv[0]), Vexec_suffixes, &path,
2062 make_number (X_OK));
2063
2064 if (NILP (path))
2065 return -1;
2066 if (posix_to_mac_pathname (SDATA (path), tempmacpathname,
2067 MAXPATHLEN+1) == 0)
2068 return -1;
2069 }
2070 strcpy (macappname, tempmacpathname);
2071 }
2072 else
2073 {
2074 if (posix_to_mac_pathname (argv[0], macappname, MAXPATHLEN+1) == 0)
2075 return -1;
2076
2077 newargv = (char **) alloca (sizeof (char *) * argc);
2078 newargc = argc;
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';
2089 if (posix_to_mac_pathname (tempcmdname, tempmaccmdname,
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];
2100 if (posix_to_mac_pathname (argv[j], tempmaccmdname,
2101 MAXPATHLEN+1) == 0)
2102 return -1;
2103 newargv[j] = (char *) alloca (strlen (tempmaccmdname)+1);
2104 strcpy (newargv[j], tempmaccmdname);
2105 }
2106 }
2107 else
2108 newargv[j] = argv[j];
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);
2129 *p++ = '\0';
2130 strcpy (p, macoutfn);
2131 p += strlen (macoutfn);
2132 *p++ = '\0';
2133 strcpy (p, macerrfn);
2134 p += strlen (macerrfn);
2135 *p++ = '\0';
2136 for (j = 1; j < newargc; j++)
2137 {
2138 strcpy (p, newargv[j]);
2139 p += strlen (newargv[j]);
2140 *p++ = '\0';
2141 }
2142
2143 c2pstr (macappname);
2144
2145 iErr = FSMakeFSSpec (0, 0, macappname, &spec);
2146
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 ();
2187
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;
2195
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 }
2204
2205 DisposeHandle ((Handle) cursor_region_handle);
2206 free (param);
2207
2208 return ref_con;
2209 #endif /* not TARGET_API_MAC_CARBON */
2210 }
2211
2212
2213 DIR *
2214 opendir (const char *dirname)
2215 {
2216 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
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;
2222
2223 if (find_true_pathname (dirname, true_pathname, MAXPATHLEN+1) == -1)
2224 return 0;
2225
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. */
2246 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
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, ":");
2253
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 */
2267
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;
2295
2296 return dirp;
2297 }
2298
2299 int
2300 closedir (DIR *dp)
2301 {
2302 free (dp);
2303
2304 return 0;
2305 }
2306
2307
2308 struct dirent *
2309 readdir (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;
2328
2329 errno = PBHGetVInfo (&hpblock, false);
2330 if (errno != noErr)
2331 {
2332 errno = ENOENT;
2333 return 0;
2334 }
2335
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;
2343
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;
2359
2360 errno = PBGetCatInfo (&cipb, false);
2361 if (errno != noErr)
2362 {
2363 errno = ENOENT;
2364 return 0;
2365 }
2366
2367 /* insist on a visible entry */
2368 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* directory? */
2369 done = !(cipb.dirInfo.ioDrUsrWds.frFlags & fInvisible);
2370 else
2371 done = !(cipb.hFileInfo.ioFlFndrInfo.fdFlags & fInvisible);
2372
2373 dp->current_index++;
2374 }
2375
2376 p2cstr (s_name);
2377
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;
2389
2390 return &s_dirent;
2391 }
2392 }
2393
2394
2395 char *
2396 getwd (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
2406 if (mac_to_posix_pathname (mac_pathname, path, MAXPATHLEN+1) == 0)
2407 return 0;
2408 else
2409 return path;
2410 }
2411
2412 #endif /* ! MAC_OSX */
2413
2414
2415 void
2416 initialize_applescript ()
2417 {
2418 AEDesc null_desc;
2419 OSAError osaerror;
2420
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
2437 void 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
2454 static long
2455 do_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
2464 if (!as_scripting_component)
2465 initialize_applescript();
2466
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 {
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 */
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);
2498 #endif /* not TARGET_API_MAC_CARBON */
2499 AEDisposeDesc (&error_desc);
2500 }
2501 }
2502 else if (osaerror == noErr) /* success: retrieve resulting script value */
2503 {
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 */
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);
2522 #endif /* not TARGET_API_MAC_CARBON */
2523 AEDisposeDesc (&result_desc);
2524 }
2525
2526 AEDisposeDesc (&script_desc);
2527
2528 return osaerror;
2529 }
2530
2531
2532 DEFUN ("do-applescript", Fdo_applescript, Sdo_applescript, 1, 1, 0,
2533 doc: /* Compile and execute AppleScript SCRIPT and retrieve and return the result.
2534 If compilation and execution are successful, the resulting script
2535 value is returned as a string. Otherwise the function aborts and
2536 displays the error message returned by the AppleScript scripting
2537 component. */)
2538 (script)
2539 Lisp_Object script;
2540 {
2541 char *result, *temp;
2542 Lisp_Object lisp_result;
2543 long status;
2544
2545 CHECK_STRING (script);
2546
2547 BLOCK_INPUT;
2548 status = do_applescript (SDATA (script), &result);
2549 UNBLOCK_INPUT;
2550 if (status)
2551 {
2552 if (!result)
2553 error ("AppleScript error %d", status);
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
2576 DEFUN ("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;
2581 {
2582 char posix_filename[MAXPATHLEN+1];
2583
2584 CHECK_STRING (mac_filename);
2585
2586 if (mac_to_posix_pathname (SDATA (mac_filename), posix_filename,
2587 MAXPATHLEN))
2588 return build_string (posix_filename);
2589 else
2590 return Qnil;
2591 }
2592
2593
2594 DEFUN ("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;
2599 {
2600 char mac_filename[MAXPATHLEN+1];
2601
2602 CHECK_STRING (posix_filename);
2603
2604 if (posix_to_mac_pathname (SDATA (posix_filename), mac_filename,
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. */
2614 DEFUN ("mac-paste-function", Fmac_paste_function, Smac_paste_function, 0, 0, 0,
2615 doc: /* Return the contents of the Mac clipboard as a string. */)
2616 ()
2617 {
2618 #if TARGET_API_MAC_CARBON
2619 OSStatus err;
2620 ScrapRef scrap;
2621 ScrapFlavorFlags sff;
2622 Size s;
2623 int i;
2624 char *data;
2625
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)
2636 return Qnil;
2637
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 */
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);
2665
2666 DisposeHandle (my_handle);
2667
2668 return value;
2669 #endif /* not TARGET_API_MAC_CARBON */
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. */
2675 DEFUN ("mac-cut-function", Fmac_cut_function, Smac_cut_function, 1, 2, 0,
2676 doc: /* Put the value of the string parameter to the Mac clipboard. */)
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
2685 CHECK_STRING (value);
2686
2687 len = SCHARS (value);
2688 buf = (char *) alloca (len+1);
2689 bcopy (SDATA (value), buf, len);
2690 buf[len] = '\0';
2691
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
2697 #if TARGET_API_MAC_CARBON
2698 {
2699 ScrapRef scrap;
2700
2701 BLOCK_INPUT;
2702 ClearCurrentScrap ();
2703 if (GetCurrentScrap (&scrap) != noErr)
2704 {
2705 UNBLOCK_INPUT;
2706 error ("cannot get current scrap");
2707 }
2708
2709 if (PutScrapFlavor (scrap, kScrapFlavorTypeText, kScrapFlavorMaskNone, len,
2710 buf) != noErr)
2711 {
2712 UNBLOCK_INPUT;
2713 error ("cannot put to scrap");
2714 }
2715 UNBLOCK_INPUT;
2716 }
2717 #else /* not TARGET_API_MAC_CARBON */
2718 ZeroScrap ();
2719 PutScrap (len, 'TEXT', buf);
2720 #endif /* not TARGET_API_MAC_CARBON */
2721
2722 return Qnil;
2723 }
2724
2725
2726 DEFUN ("x-selection-exists-p", Fx_selection_exists_p, Sx_selection_exists_p,
2727 0, 1, 0,
2728 doc: /* Whether there is an owner for the given X Selection.
2729 The arg should be the name of the selection in question, typically one of
2730 the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.
2731 \(Those are literal upper-case symbol names, since that's what X expects.)
2732 For convenience, the symbol nil is the same as `PRIMARY',
2733 and t is the same as `SECONDARY'. */)
2734 (selection)
2735 Lisp_Object selection;
2736 {
2737 CHECK_SYMBOL (selection);
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;
2745
2746 #if TARGET_API_MAC_CARBON
2747 ScrapRef scrap;
2748 ScrapFlavorFlags sff;
2749
2750 BLOCK_INPUT;
2751 if (GetCurrentScrap (&scrap) == noErr)
2752 if (GetScrapFlavorFlags (scrap, kScrapFlavorTypeText, &sff) == noErr)
2753 val = Qt;
2754 UNBLOCK_INPUT;
2755 #else /* not TARGET_API_MAC_CARBON */
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);
2766 #endif /* not TARGET_API_MAC_CARBON */
2767
2768 return val;
2769 }
2770 return Qnil;
2771 }
2772
2773 extern void mac_clear_font_name_table P_ ((void));
2774
2775 DEFUN ("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
2784 #ifdef MAC_OSX
2785 #undef select
2786
2787 extern int inhibit_window_system;
2788 extern int noninteractive;
2789
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
2818 static void
2819 socket_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
2834 static int
2835 select_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
2861 #if MAC_OS_X_VERSION_MAX_ALLOWED < 1020
2862 #undef SELECT_INVALIDATE_CFSOCKET
2863 #endif
2864
2865 int
2866 sys_select (n, rfds, wfds, efds, timeout)
2867 int n;
2868 SELECT_TYPE *rfds;
2869 SELECT_TYPE *wfds;
2870 SELECT_TYPE *efds;
2871 struct timeval *timeout;
2872 {
2873 OSErr err;
2874 int i, r;
2875 EMACS_TIME select_timeout;
2876
2877 if (inhibit_window_system || noninteractive
2878 || rfds == NULL || !FD_ISSET (0, rfds))
2879 return select (n, rfds, wfds, efds, timeout);
2880
2881 FD_CLR (0, rfds);
2882
2883 if (wfds == NULL && efds == NULL)
2884 {
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);
2893
2894 for (i = 1; i < n; i++)
2895 if (FD_ISSET (i, rfds))
2896 nsocks++;
2897
2898 if (nsocks == 0)
2899 {
2900 BLOCK_INPUT;
2901 err = ReceiveNextEvent (0, NULL, timeout_sec,
2902 kEventLeaveInQueue, NULL);
2903 UNBLOCK_INPUT;
2904 if (err == noErr)
2905 {
2906 FD_SET (0, rfds);
2907 return 1;
2908 }
2909 else
2910 return 0;
2911 }
2912
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;
2919
2920 *rfds = orfds;
2921
2922 #ifdef SELECT_USE_CFSOCKET
2923 if (timeout_sec > 0 && timeout_sec <= SELECT_TIMEOUT_THRESHOLD_RUNLOOP)
2924 goto poll_periodically;
2925
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))
2946 {
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++;
2965 }
2966
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 */
3002 }
3003
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 }
3050 }
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. */
3062 void
3063 init_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);
3143 strcat (p, "/Contents/MacOS/libexec");
3144 if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
3145 strcat (q, p);
3146
3147 strcpy (p, app_bundle_pathname);
3148 strcat (p, "/Contents/MacOS/bin");
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 }
3184 #endif /* MAC_OSX */
3185
3186 void
3187 syms_of_mac ()
3188 {
3189 QCLIPBOARD = intern ("CLIPBOARD");
3190 staticpro (&QCLIPBOARD);
3191
3192 defsubr (&Smac_paste_function);
3193 defsubr (&Smac_cut_function);
3194 defsubr (&Sx_selection_exists_p);
3195 defsubr (&Smac_clear_font_name_table);
3196
3197 defsubr (&Sdo_applescript);
3198 defsubr (&Smac_file_name_to_posix);
3199 defsubr (&Sposix_file_name_to_mac);
3200 }
3201
3202 /* arch-tag: 29d30c1f-0c6b-4f88-8a6d-0558d7f9dbff
3203 (do not change this comment) */