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