1 /* Unix emulation routines for GNU Emacs on the Mac OS.
2 Copyright (C) 2000, 2001, 2002, 2003, 2004,
3 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA. */
22 /* Contributed by Andrew Choi (akochoi@mac.com). */
35 #include "sysselect.h"
36 #include "blockinput.h"
42 #if !TARGET_API_MAC_CARBON
45 #include <TextUtils.h>
47 #include <Resources.h>
51 #include <AppleScript.h>
53 #include <Processes.h>
55 #include <MacLocales.h>
57 #endif /* not TARGET_API_MAC_CARBON */
61 #include <sys/types.h>
65 #include <sys/param.h>
71 /* The system script code. */
72 static int mac_system_script_code
;
74 /* The system locale identifier string. */
75 static Lisp_Object Vmac_system_locale
;
77 /* An instance of the AppleScript component. */
78 static ComponentInstance as_scripting_component
;
79 /* The single script context used for all script executions. */
80 static OSAID as_script_context
;
83 #if TARGET_API_MAC_CARBON
84 static int wakeup_from_rne_enabled_p
= 0;
85 #define ENABLE_WAKEUP_FROM_RNE (wakeup_from_rne_enabled_p = 1)
86 #define DISABLE_WAKEUP_FROM_RNE (wakeup_from_rne_enabled_p = 0)
88 #define ENABLE_WAKEUP_FROM_RNE 0
89 #define DISABLE_WAKEUP_FROM_RNE 0
94 static OSErr posix_pathname_to_fsspec
P_ ((const char *, FSSpec
*));
95 static OSErr fsspec_to_posix_pathname
P_ ((const FSSpec
*, char *, int));
98 /* When converting from Mac to Unix pathnames, /'s in folder names are
99 converted to :'s. This function, used in copying folder names,
100 performs a strncat and converts all character a to b in the copy of
101 the string s2 appended to the end of s1. */
104 string_cat_and_replace (char *s1
, const char *s2
, int n
, char a
, char b
)
106 int l1
= strlen (s1
);
107 int l2
= strlen (s2
);
112 for (i
= 0; i
< l2
; i
++)
121 /* Convert a Mac pathname to Posix form. A Mac full pathname is one
122 that does not begin with a ':' and contains at least one ':'. A Mac
123 full pathname causes a '/' to be prepended to the Posix pathname.
124 The algorithm for the rest of the pathname is as follows:
125 For each segment between two ':',
126 if it is non-null, copy as is and then add a '/' at the end,
127 otherwise, insert a "../" into the Posix pathname.
128 Returns 1 if successful; 0 if fails. */
131 mac_to_posix_pathname (const char *mfn
, char *ufn
, int ufnbuflen
)
133 const char *p
, *q
, *pe
;
140 p
= strchr (mfn
, ':');
141 if (p
!= 0 && p
!= mfn
) /* full pathname */
148 pe
= mfn
+ strlen (mfn
);
155 { /* two consecutive ':' */
156 if (strlen (ufn
) + 3 >= ufnbuflen
)
162 if (strlen (ufn
) + (q
- p
) + 1 >= ufnbuflen
)
164 string_cat_and_replace (ufn
, p
, q
- p
, '/', ':');
171 if (strlen (ufn
) + (pe
- p
) >= ufnbuflen
)
173 string_cat_and_replace (ufn
, p
, pe
- p
, '/', ':');
174 /* no separator for last one */
183 extern char *get_temp_dir_name ();
186 /* Convert a Posix pathname to Mac form. Approximately reverse of the
187 above in algorithm. */
190 posix_to_mac_pathname (const char *ufn
, char *mfn
, int mfnbuflen
)
192 const char *p
, *q
, *pe
;
193 char expanded_pathname
[MAXPATHLEN
+1];
202 /* Check for and handle volume names. Last comparison: strangely
203 somewhere "/.emacs" is passed. A temporary fix for now. */
204 if (*p
== '/' && strchr (p
+1, '/') == NULL
&& strcmp (p
, "/.emacs") != 0)
206 if (strlen (p
) + 1 > mfnbuflen
)
213 /* expand to emacs dir found by init_emacs_passwd_dir */
214 if (strncmp (p
, "~emacs/", 7) == 0)
216 struct passwd
*pw
= getpwnam ("emacs");
218 if (strlen (pw
->pw_dir
) + strlen (p
) > MAXPATHLEN
)
220 strcpy (expanded_pathname
, pw
->pw_dir
);
221 strcat (expanded_pathname
, p
);
222 p
= expanded_pathname
;
223 /* now p points to the pathname with emacs dir prefix */
225 else if (strncmp (p
, "/tmp/", 5) == 0)
227 char *t
= get_temp_dir_name ();
229 if (strlen (t
) + strlen (p
) > MAXPATHLEN
)
231 strcpy (expanded_pathname
, t
);
232 strcat (expanded_pathname
, p
);
233 p
= expanded_pathname
;
234 /* now p points to the pathname with emacs dir prefix */
236 else if (*p
!= '/') /* relative pathname */
248 if (q
- p
== 2 && *p
== '.' && *(p
+1) == '.')
250 if (strlen (mfn
) + 1 >= mfnbuflen
)
256 if (strlen (mfn
) + (q
- p
) + 1 >= mfnbuflen
)
258 string_cat_and_replace (mfn
, p
, q
- p
, ':', '/');
265 if (strlen (mfn
) + (pe
- p
) >= mfnbuflen
)
267 string_cat_and_replace (mfn
, p
, pe
- p
, ':', '/');
276 /***********************************************************************
277 Conversions on Apple event objects
278 ***********************************************************************/
280 static Lisp_Object Qundecoded_file_name
;
287 {{keyTransactionIDAttr
, "transaction-id"},
288 {keyReturnIDAttr
, "return-id"},
289 {keyEventClassAttr
, "event-class"},
290 {keyEventIDAttr
, "event-id"},
291 {keyAddressAttr
, "address"},
292 {keyOptionalKeywordAttr
, "optional-keyword"},
293 {keyTimeoutAttr
, "timeout"},
294 {keyInteractLevelAttr
, "interact-level"},
295 {keyEventSourceAttr
, "event-source"},
296 /* {keyMissedKeywordAttr, "missed-keyword"}, */
297 {keyOriginalAddressAttr
, "original-address"},
298 {keyReplyRequestedAttr
, "reply-requested"},
299 {KEY_EMACS_SUSPENSION_ID_ATTR
, "emacs-suspension-id"}
303 mac_aelist_to_lisp (desc_list
)
304 const AEDescList
*desc_list
;
308 Lisp_Object result
, elem
;
315 err
= AECountItems (desc_list
, &count
);
325 keyword
= ae_attr_table
[count
- 1].keyword
;
326 err
= AESizeOfAttribute (desc_list
, keyword
, &desc_type
, &size
);
329 err
= AESizeOfNthItem (desc_list
, count
, &desc_type
, &size
);
338 err
= AEGetAttributeDesc (desc_list
, keyword
, typeWildCard
,
341 err
= AEGetNthDesc (desc_list
, count
, typeWildCard
,
345 elem
= mac_aelist_to_lisp (&desc
);
346 AEDisposeDesc (&desc
);
350 if (desc_type
== typeNull
)
354 elem
= make_uninit_string (size
);
356 err
= AEGetAttributePtr (desc_list
, keyword
, typeWildCard
,
357 &desc_type
, SDATA (elem
),
360 err
= AEGetNthPtr (desc_list
, count
, typeWildCard
, &keyword
,
361 &desc_type
, SDATA (elem
), size
, &size
);
365 desc_type
= EndianU32_NtoB (desc_type
);
366 elem
= Fcons (make_unibyte_string ((char *) &desc_type
, 4), elem
);
370 if (err
== noErr
|| desc_list
->descriptorType
== typeAEList
)
373 elem
= Qnil
; /* Don't skip elements in AEList. */
374 else if (desc_list
->descriptorType
!= typeAEList
)
377 elem
= Fcons (ae_attr_table
[count
-1].symbol
, elem
);
380 keyword
= EndianU32_NtoB (keyword
);
381 elem
= Fcons (make_unibyte_string ((char *) &keyword
, 4),
386 result
= Fcons (elem
, result
);
392 if (desc_list
->descriptorType
== typeAppleEvent
&& !attribute_p
)
395 count
= sizeof (ae_attr_table
) / sizeof (ae_attr_table
[0]);
399 desc_type
= EndianU32_NtoB (desc_list
->descriptorType
);
400 return Fcons (make_unibyte_string ((char *) &desc_type
, 4), result
);
404 mac_aedesc_to_lisp (desc
)
408 DescType desc_type
= desc
->descriptorType
;
420 return mac_aelist_to_lisp (desc
);
422 /* The following one is much simpler, but creates and disposes
423 of Apple event descriptors many times. */
430 err
= AECountItems (desc
, &count
);
436 err
= AEGetNthDesc (desc
, count
, typeWildCard
, &keyword
, &desc1
);
439 elem
= mac_aedesc_to_lisp (&desc1
);
440 AEDisposeDesc (&desc1
);
441 if (desc_type
!= typeAEList
)
443 keyword
= EndianU32_NtoB (keyword
);
444 elem
= Fcons (make_unibyte_string ((char *) &keyword
, 4), elem
);
446 result
= Fcons (elem
, result
);
454 #if TARGET_API_MAC_CARBON
455 result
= make_uninit_string (AEGetDescDataSize (desc
));
456 err
= AEGetDescData (desc
, SDATA (result
), SBYTES (result
));
458 result
= make_uninit_string (GetHandleSize (desc
->dataHandle
));
459 memcpy (SDATA (result
), *(desc
->dataHandle
), SBYTES (result
));
467 desc_type
= EndianU32_NtoB (desc_type
);
468 return Fcons (make_unibyte_string ((char *) &desc_type
, 4), result
);
472 mac_ae_put_lisp (desc
, keyword_or_index
, obj
)
474 UInt32 keyword_or_index
;
479 if (!(desc
->descriptorType
== typeAppleEvent
480 || desc
->descriptorType
== typeAERecord
481 || desc
->descriptorType
== typeAEList
))
482 return errAEWrongDataType
;
484 if (CONSP (obj
) && STRINGP (XCAR (obj
)) && SBYTES (XCAR (obj
)) == 4)
486 DescType desc_type1
= EndianU32_BtoN (*((UInt32
*) SDATA (XCAR (obj
))));
487 Lisp_Object data
= XCDR (obj
), rest
;
498 err
= AECreateList (NULL
, 0, desc_type1
== typeAERecord
, &desc1
);
501 for (rest
= data
; CONSP (rest
); rest
= XCDR (rest
))
503 UInt32 keyword_or_index1
= 0;
504 Lisp_Object elem
= XCAR (rest
);
506 if (desc_type1
== typeAERecord
)
508 if (CONSP (elem
) && STRINGP (XCAR (elem
))
509 && SBYTES (XCAR (elem
)) == 4)
512 EndianU32_BtoN (*((UInt32
*)
513 SDATA (XCAR (elem
))));
520 err
= mac_ae_put_lisp (&desc1
, keyword_or_index1
, elem
);
527 if (desc
->descriptorType
== typeAEList
)
528 err
= AEPutDesc (desc
, keyword_or_index
, &desc1
);
530 err
= AEPutParamDesc (desc
, keyword_or_index
, &desc1
);
533 AEDisposeDesc (&desc1
);
540 if (desc
->descriptorType
== typeAEList
)
541 err
= AEPutPtr (desc
, keyword_or_index
, desc_type1
,
542 SDATA (data
), SBYTES (data
));
544 err
= AEPutParamPtr (desc
, keyword_or_index
, desc_type1
,
545 SDATA (data
), SBYTES (data
));
550 if (desc
->descriptorType
== typeAEList
)
551 err
= AEPutPtr (desc
, keyword_or_index
, typeNull
, NULL
, 0);
553 err
= AEPutParamPtr (desc
, keyword_or_index
, typeNull
, NULL
, 0);
559 mac_coerce_file_name_ptr (type_code
, data_ptr
, data_size
,
560 to_type
, handler_refcon
, result
)
562 const void *data_ptr
;
570 if (type_code
== typeNull
)
571 err
= errAECoercionFail
;
572 else if (type_code
== to_type
|| to_type
== typeWildCard
)
573 err
= AECreateDesc (TYPE_FILE_NAME
, data_ptr
, data_size
, result
);
574 else if (type_code
== TYPE_FILE_NAME
)
575 /* Coercion from undecoded file name. */
580 CFDataRef data
= NULL
;
582 str
= CFStringCreateWithBytes (NULL
, data_ptr
, data_size
,
583 kCFStringEncodingUTF8
, false);
586 url
= CFURLCreateWithFileSystemPath (NULL
, str
,
587 kCFURLPOSIXPathStyle
, false);
592 data
= CFURLCreateData (NULL
, url
, kCFStringEncodingUTF8
, true);
597 err
= AECoercePtr (typeFileURL
, CFDataGetBytePtr (data
),
598 CFDataGetLength (data
), to_type
, result
);
606 /* Just to be paranoid ... */
610 buf
= xmalloc (data_size
+ 1);
611 memcpy (buf
, data_ptr
, data_size
);
612 buf
[data_size
] = '\0';
613 err
= FSPathMakeRef (buf
, &fref
, NULL
);
616 err
= AECoercePtr (typeFSRef
, &fref
, sizeof (FSRef
),
623 buf
= xmalloc (data_size
+ 1);
624 memcpy (buf
, data_ptr
, data_size
);
625 buf
[data_size
] = '\0';
626 err
= posix_pathname_to_fsspec (buf
, &fs
);
629 err
= AECoercePtr (typeFSS
, &fs
, sizeof (FSSpec
), to_type
, result
);
632 else if (to_type
== TYPE_FILE_NAME
)
633 /* Coercion to undecoded file name. */
637 CFStringRef str
= NULL
;
638 CFDataRef data
= NULL
;
640 if (type_code
== typeFileURL
)
641 url
= CFURLCreateWithBytes (NULL
, data_ptr
, data_size
,
642 kCFStringEncodingUTF8
, NULL
);
649 err
= AECoercePtr (type_code
, data_ptr
, data_size
,
653 size
= AEGetDescDataSize (&desc
);
654 buf
= xmalloc (size
);
655 err
= AEGetDescData (&desc
, buf
, size
);
657 url
= CFURLCreateWithBytes (NULL
, buf
, size
,
658 kCFStringEncodingUTF8
, NULL
);
660 AEDisposeDesc (&desc
);
665 str
= CFURLCopyFileSystemPath (url
, kCFURLPOSIXPathStyle
);
670 data
= CFStringCreateExternalRepresentation (NULL
, str
,
671 kCFStringEncodingUTF8
,
677 err
= AECreateDesc (TYPE_FILE_NAME
, CFDataGetBytePtr (data
),
678 CFDataGetLength (data
), result
);
684 /* Coercion from typeAlias to typeFileURL fails on Mac OS X
685 10.2. In such cases, try typeFSRef as a target type. */
686 char file_name
[MAXPATHLEN
];
688 if (type_code
== typeFSRef
&& data_size
== sizeof (FSRef
))
689 err
= FSRefMakePath (data_ptr
, file_name
, sizeof (file_name
));
695 err
= AECoercePtr (type_code
, data_ptr
, data_size
,
699 err
= AEGetDescData (&desc
, &fref
, sizeof (FSRef
));
700 AEDisposeDesc (&desc
);
703 err
= FSRefMakePath (&fref
, file_name
, sizeof (file_name
));
706 err
= AECreateDesc (TYPE_FILE_NAME
, file_name
,
707 strlen (file_name
), result
);
710 char file_name
[MAXPATHLEN
];
712 if (type_code
== typeFSS
&& data_size
== sizeof (FSSpec
))
713 err
= fsspec_to_posix_pathname (data_ptr
, file_name
,
714 sizeof (file_name
) - 1);
720 err
= AECoercePtr (type_code
, data_ptr
, data_size
, typeFSS
, &desc
);
723 #if TARGET_API_MAC_CARBON
724 err
= AEGetDescData (&desc
, &fs
, sizeof (FSSpec
));
726 fs
= *(FSSpec
*)(*(desc
.dataHandle
));
728 AEDisposeDesc (&desc
);
731 err
= fsspec_to_posix_pathname (&fs
, file_name
,
732 sizeof (file_name
) - 1);
735 err
= AECreateDesc (TYPE_FILE_NAME
, file_name
,
736 strlen (file_name
), result
);
743 return errAECoercionFail
;
748 mac_coerce_file_name_desc (from_desc
, to_type
, handler_refcon
, result
)
749 const AEDesc
*from_desc
;
755 DescType from_type
= from_desc
->descriptorType
;
757 if (from_type
== typeNull
)
758 err
= errAECoercionFail
;
759 else if (from_type
== to_type
|| to_type
== typeWildCard
)
760 err
= AEDuplicateDesc (from_desc
, result
);
766 #if TARGET_API_MAC_CARBON
767 data_size
= AEGetDescDataSize (from_desc
);
769 data_size
= GetHandleSize (from_desc
->dataHandle
);
771 data_ptr
= xmalloc (data_size
);
772 #if TARGET_API_MAC_CARBON
773 err
= AEGetDescData (from_desc
, data_ptr
, data_size
);
775 memcpy (data_ptr
, *(from_desc
->dataHandle
), data_size
);
778 err
= mac_coerce_file_name_ptr (from_type
, data_ptr
,
780 handler_refcon
, result
);
785 return errAECoercionFail
;
790 init_coercion_handler ()
794 static AECoercePtrUPP coerce_file_name_ptrUPP
= NULL
;
795 static AECoerceDescUPP coerce_file_name_descUPP
= NULL
;
797 if (coerce_file_name_ptrUPP
== NULL
)
799 coerce_file_name_ptrUPP
= NewAECoercePtrUPP (mac_coerce_file_name_ptr
);
800 coerce_file_name_descUPP
= NewAECoerceDescUPP (mac_coerce_file_name_desc
);
803 err
= AEInstallCoercionHandler (TYPE_FILE_NAME
, typeWildCard
,
804 (AECoercionHandlerUPP
)
805 coerce_file_name_ptrUPP
, 0, false, false);
807 err
= AEInstallCoercionHandler (typeWildCard
, TYPE_FILE_NAME
,
808 (AECoercionHandlerUPP
)
809 coerce_file_name_ptrUPP
, 0, false, false);
811 err
= AEInstallCoercionHandler (TYPE_FILE_NAME
, typeWildCard
,
812 coerce_file_name_descUPP
, 0, true, false);
814 err
= AEInstallCoercionHandler (typeWildCard
, TYPE_FILE_NAME
,
815 coerce_file_name_descUPP
, 0, true, false);
819 #if TARGET_API_MAC_CARBON
821 create_apple_event (class, id
, result
)
827 static const ProcessSerialNumber psn
= {0, kCurrentProcess
};
828 AEAddressDesc address_desc
;
830 err
= AECreateDesc (typeProcessSerialNumber
, &psn
,
831 sizeof (ProcessSerialNumber
), &address_desc
);
834 err
= AECreateAppleEvent (class, id
,
835 &address_desc
, /* NULL is not allowed
836 on Mac OS Classic. */
837 kAutoGenerateReturnID
,
838 kAnyTransactionID
, result
);
839 AEDisposeDesc (&address_desc
);
846 mac_event_parameters_to_lisp (event
, num_params
, names
, types
)
849 const EventParamName
*names
;
850 const EventParamType
*types
;
853 Lisp_Object result
= Qnil
;
862 for (i
= 0; i
< num_params
; i
++)
864 EventParamName name
= names
[i
];
865 EventParamType type
= types
[i
];
870 case typeCFStringRef
:
871 err
= GetEventParameter (event
, name
, typeCFStringRef
, NULL
,
872 sizeof (CFStringRef
), NULL
, &string
);
875 data
= CFStringCreateExternalRepresentation (NULL
, string
,
876 kCFStringEncodingUTF8
,
880 name
= EndianU32_NtoB (name
);
881 type
= EndianU32_NtoB (typeUTF8Text
);
883 Fcons (Fcons (make_unibyte_string ((char *) &name
, 4),
884 Fcons (make_unibyte_string ((char *) &type
, 4),
885 make_unibyte_string (CFDataGetBytePtr (data
),
886 CFDataGetLength (data
)))),
893 err
= GetEventParameter (event
, name
, type
, NULL
, 0, &size
, NULL
);
896 buf
= xrealloc (buf
, size
);
897 err
= GetEventParameter (event
, name
, type
, NULL
, size
, NULL
, buf
);
900 name
= EndianU32_NtoB (name
);
901 type
= EndianU32_NtoB (type
);
903 Fcons (Fcons (make_unibyte_string ((char *) &name
, 4),
904 Fcons (make_unibyte_string ((char *) &type
, 4),
905 make_unibyte_string (buf
, size
))),
916 #endif /* TARGET_API_MAC_CARBON */
918 /***********************************************************************
919 Conversion between Lisp and Core Foundation objects
920 ***********************************************************************/
922 #if TARGET_API_MAC_CARBON
923 static Lisp_Object Qstring
, Qnumber
, Qboolean
, Qdate
, Qdata
;
924 static Lisp_Object Qarray
, Qdictionary
;
926 struct cfdict_context
929 int with_tag
, hash_bound
;
932 /* C string to CFString. */
935 cfstring_create_with_utf8_cstring (c_str
)
940 str
= CFStringCreateWithCString (NULL
, c_str
, kCFStringEncodingUTF8
);
942 /* Failed to interpret as UTF 8. Fall back on Mac Roman. */
943 str
= CFStringCreateWithCString (NULL
, c_str
, kCFStringEncodingMacRoman
);
949 /* Lisp string to CFString. */
952 cfstring_create_with_string (s
)
955 CFStringRef string
= NULL
;
957 if (STRING_MULTIBYTE (s
))
959 char *p
, *end
= SDATA (s
) + SBYTES (s
);
961 for (p
= SDATA (s
); p
< end
; p
++)
964 s
= ENCODE_UTF_8 (s
);
967 string
= CFStringCreateWithBytes (NULL
, SDATA (s
), SBYTES (s
),
968 kCFStringEncodingUTF8
, false);
972 /* Failed to interpret as UTF 8. Fall back on Mac Roman. */
973 string
= CFStringCreateWithBytes (NULL
, SDATA (s
), SBYTES (s
),
974 kCFStringEncodingMacRoman
, false);
980 /* From CFData to a lisp string. Always returns a unibyte string. */
983 cfdata_to_lisp (data
)
986 CFIndex len
= CFDataGetLength (data
);
987 Lisp_Object result
= make_uninit_string (len
);
989 CFDataGetBytes (data
, CFRangeMake (0, len
), SDATA (result
));
995 /* From CFString to a lisp string. Returns a unibyte string
996 containing a UTF-8 byte sequence. */
999 cfstring_to_lisp_nodecode (string
)
1002 Lisp_Object result
= Qnil
;
1003 const char *s
= CFStringGetCStringPtr (string
, kCFStringEncodingUTF8
);
1006 result
= make_unibyte_string (s
, strlen (s
));
1010 CFStringCreateExternalRepresentation (NULL
, string
,
1011 kCFStringEncodingUTF8
, '?');
1015 result
= cfdata_to_lisp (data
);
1024 /* From CFString to a lisp string. Never returns a unibyte string
1025 (even if it only contains ASCII characters).
1026 This may cause GC during code conversion. */
1029 cfstring_to_lisp (string
)
1032 Lisp_Object result
= cfstring_to_lisp_nodecode (string
);
1036 result
= code_convert_string_norecord (result
, Qutf_8
, 0);
1037 /* This may be superfluous. Just to make sure that the result
1038 is a multibyte string. */
1039 result
= string_to_multibyte (result
);
1046 /* CFNumber to a lisp integer or a lisp float. */
1049 cfnumber_to_lisp (number
)
1052 Lisp_Object result
= Qnil
;
1053 #if BITS_PER_EMACS_INT > 32
1055 CFNumberType emacs_int_type
= kCFNumberSInt64Type
;
1058 CFNumberType emacs_int_type
= kCFNumberSInt32Type
;
1062 if (CFNumberGetValue (number
, emacs_int_type
, &int_val
)
1063 && !FIXNUM_OVERFLOW_P (int_val
))
1064 result
= make_number (int_val
);
1066 if (CFNumberGetValue (number
, kCFNumberDoubleType
, &float_val
))
1067 result
= make_float (float_val
);
1072 /* CFDate to a list of three integers as in a return value of
1076 cfdate_to_lisp (date
)
1080 int high
, low
, microsec
;
1082 sec
= CFDateGetAbsoluteTime (date
) + kCFAbsoluteTimeIntervalSince1970
;
1083 high
= sec
/ 65536.0;
1084 low
= sec
- high
* 65536.0;
1085 microsec
= (sec
- floor (sec
)) * 1000000.0;
1087 return list3 (make_number (high
), make_number (low
), make_number (microsec
));
1091 /* CFBoolean to a lisp symbol, `t' or `nil'. */
1094 cfboolean_to_lisp (boolean
)
1095 CFBooleanRef boolean
;
1097 return CFBooleanGetValue (boolean
) ? Qt
: Qnil
;
1101 /* Any Core Foundation object to a (lengthy) lisp string. */
1104 cfobject_desc_to_lisp (object
)
1107 Lisp_Object result
= Qnil
;
1108 CFStringRef desc
= CFCopyDescription (object
);
1112 result
= cfstring_to_lisp (desc
);
1120 /* Callback functions for cfproperty_list_to_lisp. */
1123 cfdictionary_add_to_list (key
, value
, context
)
1128 struct cfdict_context
*cxt
= (struct cfdict_context
*)context
;
1131 Fcons (Fcons (cfstring_to_lisp (key
),
1132 cfproperty_list_to_lisp (value
, cxt
->with_tag
,
1138 cfdictionary_puthash (key
, value
, context
)
1143 Lisp_Object lisp_key
= cfstring_to_lisp (key
);
1144 struct cfdict_context
*cxt
= (struct cfdict_context
*)context
;
1145 struct Lisp_Hash_Table
*h
= XHASH_TABLE (*(cxt
->result
));
1148 hash_lookup (h
, lisp_key
, &hash_code
);
1149 hash_put (h
, lisp_key
,
1150 cfproperty_list_to_lisp (value
, cxt
->with_tag
, cxt
->hash_bound
),
1155 /* Convert CFPropertyList PLIST to a lisp object. If WITH_TAG is
1156 non-zero, a symbol that represents the type of the original Core
1157 Foundation object is prepended. HASH_BOUND specifies which kinds
1158 of the lisp objects, alists or hash tables, are used as the targets
1159 of the conversion from CFDictionary. If HASH_BOUND is negative,
1160 always generate alists. If HASH_BOUND >= 0, generate an alist if
1161 the number of keys in the dictionary is smaller than HASH_BOUND,
1162 and a hash table otherwise. */
1165 cfproperty_list_to_lisp (plist
, with_tag
, hash_bound
)
1166 CFPropertyListRef plist
;
1167 int with_tag
, hash_bound
;
1169 CFTypeID type_id
= CFGetTypeID (plist
);
1170 Lisp_Object tag
= Qnil
, result
= Qnil
;
1171 struct gcpro gcpro1
, gcpro2
;
1173 GCPRO2 (tag
, result
);
1175 if (type_id
== CFStringGetTypeID ())
1178 result
= cfstring_to_lisp (plist
);
1180 else if (type_id
== CFNumberGetTypeID ())
1183 result
= cfnumber_to_lisp (plist
);
1185 else if (type_id
== CFBooleanGetTypeID ())
1188 result
= cfboolean_to_lisp (plist
);
1190 else if (type_id
== CFDateGetTypeID ())
1193 result
= cfdate_to_lisp (plist
);
1195 else if (type_id
== CFDataGetTypeID ())
1198 result
= cfdata_to_lisp (plist
);
1200 else if (type_id
== CFArrayGetTypeID ())
1202 CFIndex index
, count
= CFArrayGetCount (plist
);
1205 result
= Fmake_vector (make_number (count
), Qnil
);
1206 for (index
= 0; index
< count
; index
++)
1207 XVECTOR (result
)->contents
[index
] =
1208 cfproperty_list_to_lisp (CFArrayGetValueAtIndex (plist
, index
),
1209 with_tag
, hash_bound
);
1211 else if (type_id
== CFDictionaryGetTypeID ())
1213 struct cfdict_context context
;
1214 CFIndex count
= CFDictionaryGetCount (plist
);
1217 context
.result
= &result
;
1218 context
.with_tag
= with_tag
;
1219 context
.hash_bound
= hash_bound
;
1220 if (hash_bound
< 0 || count
< hash_bound
)
1223 CFDictionaryApplyFunction (plist
, cfdictionary_add_to_list
,
1228 result
= make_hash_table (Qequal
,
1229 make_number (count
),
1230 make_float (DEFAULT_REHASH_SIZE
),
1231 make_float (DEFAULT_REHASH_THRESHOLD
),
1233 CFDictionaryApplyFunction (plist
, cfdictionary_puthash
,
1243 result
= Fcons (tag
, result
);
1250 /***********************************************************************
1251 Emulation of the X Resource Manager
1252 ***********************************************************************/
1254 /* Parser functions for resource lines. Each function takes an
1255 address of a variable whose value points to the head of a string.
1256 The value will be advanced so that it points to the next character
1257 of the parsed part when the function returns.
1259 A resource name such as "Emacs*font" is parsed into a non-empty
1260 list called `quarks'. Each element is either a Lisp string that
1261 represents a concrete component, a Lisp symbol LOOSE_BINDING
1262 (actually Qlambda) that represents any number (>=0) of intervening
1263 components, or a Lisp symbol SINGLE_COMPONENT (actually Qquote)
1264 that represents as any single component. */
1268 #define LOOSE_BINDING Qlambda /* '*' ("L"oose) */
1269 #define SINGLE_COMPONENT Qquote /* '?' ("Q"uestion) */
1272 skip_white_space (p
)
1275 /* WhiteSpace = {<space> | <horizontal tab>} */
1276 while (*P
== ' ' || *P
== '\t')
1284 /* Comment = "!" {<any character except null or newline>} */
1297 /* Don't interpret filename. Just skip until the newline. */
1299 parse_include_file (p
)
1302 /* IncludeFile = "#" WhiteSpace "include" WhiteSpace FileName WhiteSpace */
1319 /* Binding = "." | "*" */
1320 if (*P
== '.' || *P
== '*')
1322 char binding
= *P
++;
1324 while (*P
== '.' || *P
== '*')
1337 /* Component = "?" | ComponentName
1338 ComponentName = NameChar {NameChar}
1339 NameChar = "a"-"z" | "A"-"Z" | "0"-"9" | "_" | "-" */
1343 return SINGLE_COMPONENT
;
1345 else if (isalnum (*P
) || *P
== '_' || *P
== '-')
1347 const char *start
= P
++;
1349 while (isalnum (*P
) || *P
== '_' || *P
== '-')
1352 return make_unibyte_string (start
, P
- start
);
1359 parse_resource_name (p
)
1362 Lisp_Object result
= Qnil
, component
;
1365 /* ResourceName = [Binding] {Component Binding} ComponentName */
1366 if (parse_binding (p
) == '*')
1367 result
= Fcons (LOOSE_BINDING
, result
);
1369 component
= parse_component (p
);
1370 if (NILP (component
))
1373 result
= Fcons (component
, result
);
1374 while ((binding
= parse_binding (p
)) != '\0')
1377 result
= Fcons (LOOSE_BINDING
, result
);
1378 component
= parse_component (p
);
1379 if (NILP (component
))
1382 result
= Fcons (component
, result
);
1385 /* The final component should not be '?'. */
1386 if (EQ (component
, SINGLE_COMPONENT
))
1389 return Fnreverse (result
);
1397 Lisp_Object seq
= Qnil
, result
;
1398 int buf_len
, total_len
= 0, len
, continue_p
;
1400 q
= strchr (P
, '\n');
1401 buf_len
= q
? q
- P
: strlen (P
);
1402 buf
= xmalloc (buf_len
);
1415 else if (*P
== '\\')
1420 else if (*P
== '\n')
1431 else if ('0' <= P
[0] && P
[0] <= '7'
1432 && '0' <= P
[1] && P
[1] <= '7'
1433 && '0' <= P
[2] && P
[2] <= '7')
1435 *q
++ = ((P
[0] - '0') << 6) + ((P
[1] - '0') << 3) + (P
[2] - '0');
1445 seq
= Fcons (make_unibyte_string (buf
, len
), seq
);
1450 q
= strchr (P
, '\n');
1451 len
= q
? q
- P
: strlen (P
);
1456 buf
= xmalloc (buf_len
);
1464 if (SBYTES (XCAR (seq
)) == total_len
)
1465 return make_string (SDATA (XCAR (seq
)), total_len
);
1468 buf
= xmalloc (total_len
);
1469 q
= buf
+ total_len
;
1470 for (; CONSP (seq
); seq
= XCDR (seq
))
1472 len
= SBYTES (XCAR (seq
));
1474 memcpy (q
, SDATA (XCAR (seq
)), len
);
1476 result
= make_string (buf
, total_len
);
1483 parse_resource_line (p
)
1486 Lisp_Object quarks
, value
;
1488 /* ResourceLine = Comment | IncludeFile | ResourceSpec | <empty line> */
1489 if (parse_comment (p
) || parse_include_file (p
))
1492 /* ResourceSpec = WhiteSpace ResourceName WhiteSpace ":" WhiteSpace Value */
1493 skip_white_space (p
);
1494 quarks
= parse_resource_name (p
);
1497 skip_white_space (p
);
1501 skip_white_space (p
);
1502 value
= parse_value (p
);
1503 return Fcons (quarks
, value
);
1506 /* Skip the remaining data as a dummy value. */
1513 /* Equivalents of X Resource Manager functions.
1515 An X Resource Database acts as a collection of resource names and
1516 associated values. It is implemented as a trie on quarks. Namely,
1517 each edge is labeled by either a string, LOOSE_BINDING, or
1518 SINGLE_COMPONENT. Each node has a node id, which is a unique
1519 nonnegative integer, and the root node id is 0. A database is
1520 implemented as a hash table that maps a pair (SRC-NODE-ID .
1521 EDGE-LABEL) to DEST-NODE-ID. It also holds a maximum node id used
1522 in the table as a value for HASHKEY_MAX_NID. A value associated to
1523 a node is recorded as a value for the node id.
1525 A database also has a cache for past queries as a value for
1526 HASHKEY_QUERY_CACHE. It is another hash table that maps
1527 "NAME-STRING\0CLASS-STRING" to the result of the query. */
1529 #define HASHKEY_MAX_NID (make_number (0))
1530 #define HASHKEY_QUERY_CACHE (make_number (-1))
1533 xrm_create_database ()
1535 XrmDatabase database
;
1537 database
= make_hash_table (Qequal
, make_number (DEFAULT_HASH_SIZE
),
1538 make_float (DEFAULT_REHASH_SIZE
),
1539 make_float (DEFAULT_REHASH_THRESHOLD
),
1541 Fputhash (HASHKEY_MAX_NID
, make_number (0), database
);
1542 Fputhash (HASHKEY_QUERY_CACHE
, Qnil
, database
);
1548 xrm_q_put_resource (database
, quarks
, value
)
1549 XrmDatabase database
;
1550 Lisp_Object quarks
, value
;
1552 struct Lisp_Hash_Table
*h
= XHASH_TABLE (database
);
1555 Lisp_Object node_id
, key
;
1557 max_nid
= XINT (Fgethash (HASHKEY_MAX_NID
, database
, Qnil
));
1559 XSETINT (node_id
, 0);
1560 for (; CONSP (quarks
); quarks
= XCDR (quarks
))
1562 key
= Fcons (node_id
, XCAR (quarks
));
1563 i
= hash_lookup (h
, key
, &hash_code
);
1567 XSETINT (node_id
, max_nid
);
1568 hash_put (h
, key
, node_id
, hash_code
);
1571 node_id
= HASH_VALUE (h
, i
);
1573 Fputhash (node_id
, value
, database
);
1575 Fputhash (HASHKEY_MAX_NID
, make_number (max_nid
), database
);
1576 Fputhash (HASHKEY_QUERY_CACHE
, Qnil
, database
);
1579 /* Merge multiple resource entries specified by DATA into a resource
1580 database DATABASE. DATA points to the head of a null-terminated
1581 string consisting of multiple resource lines. It's like a
1582 combination of XrmGetStringDatabase and XrmMergeDatabases. */
1585 xrm_merge_string_database (database
, data
)
1586 XrmDatabase database
;
1589 Lisp_Object quarks_value
;
1593 quarks_value
= parse_resource_line (&data
);
1594 if (!NILP (quarks_value
))
1595 xrm_q_put_resource (database
,
1596 XCAR (quarks_value
), XCDR (quarks_value
));
1601 xrm_q_get_resource_1 (database
, node_id
, quark_name
, quark_class
)
1602 XrmDatabase database
;
1603 Lisp_Object node_id
, quark_name
, quark_class
;
1605 struct Lisp_Hash_Table
*h
= XHASH_TABLE (database
);
1606 Lisp_Object key
, labels
[3], value
;
1609 if (!CONSP (quark_name
))
1610 return Fgethash (node_id
, database
, Qnil
);
1612 /* First, try tight bindings */
1613 labels
[0] = XCAR (quark_name
);
1614 labels
[1] = XCAR (quark_class
);
1615 labels
[2] = SINGLE_COMPONENT
;
1617 key
= Fcons (node_id
, Qnil
);
1618 for (k
= 0; k
< sizeof (labels
) / sizeof (*labels
); k
++)
1620 XSETCDR (key
, labels
[k
]);
1621 i
= hash_lookup (h
, key
, NULL
);
1624 value
= xrm_q_get_resource_1 (database
, HASH_VALUE (h
, i
),
1625 XCDR (quark_name
), XCDR (quark_class
));
1631 /* Then, try loose bindings */
1632 XSETCDR (key
, LOOSE_BINDING
);
1633 i
= hash_lookup (h
, key
, NULL
);
1636 value
= xrm_q_get_resource_1 (database
, HASH_VALUE (h
, i
),
1637 quark_name
, quark_class
);
1641 return xrm_q_get_resource_1 (database
, node_id
,
1642 XCDR (quark_name
), XCDR (quark_class
));
1649 xrm_q_get_resource (database
, quark_name
, quark_class
)
1650 XrmDatabase database
;
1651 Lisp_Object quark_name
, quark_class
;
1653 return xrm_q_get_resource_1 (database
, make_number (0),
1654 quark_name
, quark_class
);
1657 /* Retrieve a resource value for the specified NAME and CLASS from the
1658 resource database DATABASE. It corresponds to XrmGetResource. */
1661 xrm_get_resource (database
, name
, class)
1662 XrmDatabase database
;
1663 const char *name
, *class;
1665 Lisp_Object key
, query_cache
, quark_name
, quark_class
, tmp
;
1667 struct Lisp_Hash_Table
*h
;
1671 nc
= strlen (class);
1672 key
= make_uninit_string (nn
+ nc
+ 1);
1673 strcpy (SDATA (key
), name
);
1674 strncpy (SDATA (key
) + nn
+ 1, class, nc
);
1676 query_cache
= Fgethash (HASHKEY_QUERY_CACHE
, database
, Qnil
);
1677 if (NILP (query_cache
))
1679 query_cache
= make_hash_table (Qequal
, make_number (DEFAULT_HASH_SIZE
),
1680 make_float (DEFAULT_REHASH_SIZE
),
1681 make_float (DEFAULT_REHASH_THRESHOLD
),
1683 Fputhash (HASHKEY_QUERY_CACHE
, query_cache
, database
);
1685 h
= XHASH_TABLE (query_cache
);
1686 i
= hash_lookup (h
, key
, &hash_code
);
1688 return HASH_VALUE (h
, i
);
1690 quark_name
= parse_resource_name (&name
);
1693 for (tmp
= quark_name
, nn
= 0; CONSP (tmp
); tmp
= XCDR (tmp
), nn
++)
1694 if (!STRINGP (XCAR (tmp
)))
1697 quark_class
= parse_resource_name (&class);
1700 for (tmp
= quark_class
, nc
= 0; CONSP (tmp
); tmp
= XCDR (tmp
), nc
++)
1701 if (!STRINGP (XCAR (tmp
)))
1708 tmp
= xrm_q_get_resource (database
, quark_name
, quark_class
);
1709 hash_put (h
, key
, tmp
, hash_code
);
1714 #if TARGET_API_MAC_CARBON
1716 xrm_cfproperty_list_to_value (plist
)
1717 CFPropertyListRef plist
;
1719 CFTypeID type_id
= CFGetTypeID (plist
);
1721 if (type_id
== CFStringGetTypeID ())
1722 return cfstring_to_lisp (plist
);
1723 else if (type_id
== CFNumberGetTypeID ())
1726 Lisp_Object result
= Qnil
;
1728 string
= CFStringCreateWithFormat (NULL
, NULL
, CFSTR ("%@"), plist
);
1731 result
= cfstring_to_lisp (string
);
1736 else if (type_id
== CFBooleanGetTypeID ())
1737 return build_string (CFBooleanGetValue (plist
) ? "true" : "false");
1738 else if (type_id
== CFDataGetTypeID ())
1739 return cfdata_to_lisp (plist
);
1745 /* Create a new resource database from the preferences for the
1746 application APPLICATION. APPLICATION is either a string that
1747 specifies an application ID, or NULL that represents the current
1751 xrm_get_preference_database (application
)
1752 const char *application
;
1754 #if TARGET_API_MAC_CARBON
1755 CFStringRef app_id
, *keys
, user_doms
[2], host_doms
[2];
1756 CFMutableSetRef key_set
= NULL
;
1757 CFArrayRef key_array
;
1758 CFIndex index
, count
;
1760 XrmDatabase database
;
1761 Lisp_Object quarks
= Qnil
, value
= Qnil
;
1762 CFPropertyListRef plist
;
1764 struct gcpro gcpro1
, gcpro2
, gcpro3
;
1766 user_doms
[0] = kCFPreferencesCurrentUser
;
1767 user_doms
[1] = kCFPreferencesAnyUser
;
1768 host_doms
[0] = kCFPreferencesCurrentHost
;
1769 host_doms
[1] = kCFPreferencesAnyHost
;
1771 database
= xrm_create_database ();
1773 GCPRO3 (database
, quarks
, value
);
1775 app_id
= kCFPreferencesCurrentApplication
;
1778 app_id
= cfstring_create_with_utf8_cstring (application
);
1782 if (!CFPreferencesAppSynchronize (app_id
))
1785 key_set
= CFSetCreateMutable (NULL
, 0, &kCFCopyStringSetCallBacks
);
1786 if (key_set
== NULL
)
1788 for (iu
= 0; iu
< sizeof (user_doms
) / sizeof (*user_doms
) ; iu
++)
1789 for (ih
= 0; ih
< sizeof (host_doms
) / sizeof (*host_doms
); ih
++)
1791 key_array
= CFPreferencesCopyKeyList (app_id
, user_doms
[iu
],
1795 count
= CFArrayGetCount (key_array
);
1796 for (index
= 0; index
< count
; index
++)
1797 CFSetAddValue (key_set
,
1798 CFArrayGetValueAtIndex (key_array
, index
));
1799 CFRelease (key_array
);
1803 count
= CFSetGetCount (key_set
);
1804 keys
= xmalloc (sizeof (CFStringRef
) * count
);
1805 CFSetGetValues (key_set
, (const void **)keys
);
1806 for (index
= 0; index
< count
; index
++)
1808 res_name
= SDATA (cfstring_to_lisp_nodecode (keys
[index
]));
1809 quarks
= parse_resource_name (&res_name
);
1810 if (!(NILP (quarks
) || *res_name
))
1812 plist
= CFPreferencesCopyAppValue (keys
[index
], app_id
);
1813 value
= xrm_cfproperty_list_to_value (plist
);
1816 xrm_q_put_resource (database
, quarks
, value
);
1823 CFRelease (key_set
);
1830 return xrm_create_database ();
1837 /* The following functions with "sys_" prefix are stubs to Unix
1838 functions that have already been implemented by CW or MPW. The
1839 calls to them in Emacs source course are #define'd to call the sys_
1840 versions by the header files s-mac.h. In these stubs pathnames are
1841 converted between their Unix and Mac forms. */
1844 /* Unix epoch is Jan 1, 1970 while Mac epoch is Jan 1, 1904: 66 years
1845 + 17 leap days. These are for adjusting time values returned by
1846 MacOS Toolbox functions. */
1848 #define MAC_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
1851 #if __MSL__ < 0x6000
1852 /* CW Pro 5 epoch is Jan 1, 1900 (aaarghhhhh!); remember, 1900 is not
1853 a leap year! This is for adjusting time_t values returned by MSL
1855 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 70 + 17) * 24 * 60 * 60)
1856 #else /* __MSL__ >= 0x6000 */
1857 /* CW changes Pro 6 to follow Unix! */
1858 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
1859 #endif /* __MSL__ >= 0x6000 */
1861 /* MPW library functions follow Unix (confused?). */
1862 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
1863 #else /* not __MRC__ */
1865 #endif /* not __MRC__ */
1868 /* Define our own stat function for both MrC and CW. The reason for
1869 doing this: "stat" is both the name of a struct and function name:
1870 can't use the same trick like that for sys_open, sys_close, etc. to
1871 redirect Emacs's calls to our own version that converts Unix style
1872 filenames to Mac style filename because all sorts of compilation
1873 errors will be generated if stat is #define'd to be sys_stat. */
1876 stat_noalias (const char *path
, struct stat
*buf
)
1878 char mac_pathname
[MAXPATHLEN
+1];
1881 if (posix_to_mac_pathname (path
, mac_pathname
, MAXPATHLEN
+1) == 0)
1884 c2pstr (mac_pathname
);
1885 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
1886 cipb
.hFileInfo
.ioVRefNum
= 0;
1887 cipb
.hFileInfo
.ioDirID
= 0;
1888 cipb
.hFileInfo
.ioFDirIndex
= 0;
1889 /* set to 0 to get information about specific dir or file */
1891 errno
= PBGetCatInfo (&cipb
, false);
1892 if (errno
== -43) /* -43: fnfErr defined in Errors.h */
1897 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* bit 4 = 1 for directories */
1899 buf
->st_mode
= S_IFDIR
| S_IREAD
| S_IEXEC
;
1901 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x1))
1902 buf
->st_mode
|= S_IWRITE
; /* bit 1 = 1 for locked files/directories */
1903 buf
->st_ino
= cipb
.dirInfo
.ioDrDirID
;
1904 buf
->st_dev
= cipb
.dirInfo
.ioVRefNum
;
1905 buf
->st_size
= cipb
.dirInfo
.ioDrNmFls
;
1906 /* size of dir = number of files and dirs */
1909 = cipb
.dirInfo
.ioDrMdDat
- MAC_UNIX_EPOCH_DIFF
;
1910 buf
->st_ctime
= cipb
.dirInfo
.ioDrCrDat
- MAC_UNIX_EPOCH_DIFF
;
1914 buf
->st_mode
= S_IFREG
| S_IREAD
;
1915 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x1))
1916 buf
->st_mode
|= S_IWRITE
; /* bit 1 = 1 for locked files/directories */
1917 if (cipb
.hFileInfo
.ioFlFndrInfo
.fdType
== 'APPL')
1918 buf
->st_mode
|= S_IEXEC
;
1919 buf
->st_ino
= cipb
.hFileInfo
.ioDirID
;
1920 buf
->st_dev
= cipb
.hFileInfo
.ioVRefNum
;
1921 buf
->st_size
= cipb
.hFileInfo
.ioFlLgLen
;
1924 = cipb
.hFileInfo
.ioFlMdDat
- MAC_UNIX_EPOCH_DIFF
;
1925 buf
->st_ctime
= cipb
.hFileInfo
.ioFlCrDat
- MAC_UNIX_EPOCH_DIFF
;
1928 if (cipb
.hFileInfo
.ioFlFndrInfo
.fdFlags
& 0x8000)
1930 /* identify alias files as symlinks */
1931 buf
->st_mode
&= ~S_IFREG
;
1932 buf
->st_mode
|= S_IFLNK
;
1936 buf
->st_uid
= getuid ();
1937 buf
->st_gid
= getgid ();
1945 lstat (const char *path
, struct stat
*buf
)
1948 char true_pathname
[MAXPATHLEN
+1];
1950 /* Try looking for the file without resolving aliases first. */
1951 if ((result
= stat_noalias (path
, buf
)) >= 0)
1954 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
1957 return stat_noalias (true_pathname
, buf
);
1962 stat (const char *path
, struct stat
*sb
)
1965 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
1968 if ((result
= stat_noalias (path
, sb
)) >= 0 &&
1969 ! (sb
->st_mode
& S_IFLNK
))
1972 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
1975 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
1978 fully_resolved_name
[len
] = '\0';
1979 /* in fact our readlink terminates strings */
1980 return lstat (fully_resolved_name
, sb
);
1983 return lstat (true_pathname
, sb
);
1988 /* CW defines fstat in stat.mac.c while MPW does not provide this
1989 function. Without the information of how to get from a file
1990 descriptor in MPW StdCLib to a Mac OS file spec, it should be hard
1991 to implement this function. Fortunately, there is only one place
1992 where this function is called in our configuration: in fileio.c,
1993 where only the st_dev and st_ino fields are used to determine
1994 whether two fildes point to different i-nodes to prevent copying
1995 a file onto itself equal. What we have here probably needs
1999 fstat (int fildes
, struct stat
*buf
)
2002 buf
->st_ino
= fildes
;
2003 buf
->st_mode
= S_IFREG
; /* added by T.I. for the copy-file */
2004 return 0; /* success */
2006 #endif /* __MRC__ */
2010 mkdir (const char *dirname
, int mode
)
2012 #pragma unused(mode)
2015 char true_pathname
[MAXPATHLEN
+1], mac_pathname
[MAXPATHLEN
+1];
2017 if (find_true_pathname (dirname
, true_pathname
, MAXPATHLEN
+1) == -1)
2020 if (posix_to_mac_pathname (true_pathname
, mac_pathname
, MAXPATHLEN
+1) == 0)
2023 c2pstr (mac_pathname
);
2024 hfpb
.ioNamePtr
= mac_pathname
;
2025 hfpb
.ioVRefNum
= 0; /* ignored unless name is invalid */
2026 hfpb
.ioDirID
= 0; /* parent is the root */
2028 errno
= PBDirCreate ((HParmBlkPtr
) &hfpb
, false);
2029 /* just return the Mac OSErr code for now */
2030 return errno
== noErr
? 0 : -1;
2035 sys_rmdir (const char *dirname
)
2038 char mac_pathname
[MAXPATHLEN
+1];
2040 if (posix_to_mac_pathname (dirname
, mac_pathname
, MAXPATHLEN
+1) == 0)
2043 c2pstr (mac_pathname
);
2044 hfpb
.ioNamePtr
= mac_pathname
;
2045 hfpb
.ioVRefNum
= 0; /* ignored unless name is invalid */
2046 hfpb
.ioDirID
= 0; /* parent is the root */
2048 errno
= PBHDelete ((HParmBlkPtr
) &hfpb
, false);
2049 return errno
== noErr
? 0 : -1;
2054 /* No implementation yet. */
2056 execvp (const char *path
, ...)
2060 #endif /* __MRC__ */
2064 utime (const char *path
, const struct utimbuf
*times
)
2066 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
2068 char mac_pathname
[MAXPATHLEN
+1];
2071 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
2074 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
2076 fully_resolved_name
[len
] = '\0';
2078 strcpy (fully_resolved_name
, true_pathname
);
2080 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
2083 c2pstr (mac_pathname
);
2084 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
2085 cipb
.hFileInfo
.ioVRefNum
= 0;
2086 cipb
.hFileInfo
.ioDirID
= 0;
2087 cipb
.hFileInfo
.ioFDirIndex
= 0;
2088 /* set to 0 to get information about specific dir or file */
2090 errno
= PBGetCatInfo (&cipb
, false);
2094 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* bit 4 = 1 for directories */
2097 cipb
.dirInfo
.ioDrMdDat
= times
->modtime
+ MAC_UNIX_EPOCH_DIFF
;
2099 GetDateTime (&cipb
.dirInfo
.ioDrMdDat
);
2104 cipb
.hFileInfo
.ioFlMdDat
= times
->modtime
+ MAC_UNIX_EPOCH_DIFF
;
2106 GetDateTime (&cipb
.hFileInfo
.ioFlMdDat
);
2109 errno
= PBSetCatInfo (&cipb
, false);
2110 return errno
== noErr
? 0 : -1;
2124 /* Like stat, but test for access mode in hfpb.ioFlAttrib */
2126 access (const char *path
, int mode
)
2128 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
2130 char mac_pathname
[MAXPATHLEN
+1];
2133 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
2136 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
2138 fully_resolved_name
[len
] = '\0';
2140 strcpy (fully_resolved_name
, true_pathname
);
2142 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
2145 c2pstr (mac_pathname
);
2146 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
2147 cipb
.hFileInfo
.ioVRefNum
= 0;
2148 cipb
.hFileInfo
.ioDirID
= 0;
2149 cipb
.hFileInfo
.ioFDirIndex
= 0;
2150 /* set to 0 to get information about specific dir or file */
2152 errno
= PBGetCatInfo (&cipb
, false);
2156 if (mode
== F_OK
) /* got this far, file exists */
2160 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* path refers to a directory */
2164 if (cipb
.hFileInfo
.ioFlFndrInfo
.fdType
== 'APPL')
2171 return (cipb
.hFileInfo
.ioFlAttrib
& 0x1) ? -1 : 0;
2172 /* don't allow if lock bit is on */
2178 #define DEV_NULL_FD 0x10000
2182 sys_open (const char *path
, int oflag
)
2184 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
2186 char mac_pathname
[MAXPATHLEN
+1];
2188 if (strcmp (path
, "/dev/null") == 0)
2189 return DEV_NULL_FD
; /* some bogus fd to be ignored in write */
2191 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
2194 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
2196 fully_resolved_name
[len
] = '\0';
2198 strcpy (fully_resolved_name
, true_pathname
);
2200 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
2205 int res
= open (mac_pathname
, oflag
);
2206 /* if (oflag == O_WRONLY || oflag == O_RDWR) */
2207 if (oflag
& O_CREAT
)
2208 fsetfileinfo (mac_pathname
, MAC_EMACS_CREATOR_CODE
, 'TEXT');
2210 #else /* not __MRC__ */
2211 return open (mac_pathname
, oflag
);
2212 #endif /* not __MRC__ */
2219 sys_creat (const char *path
, mode_t mode
)
2221 char true_pathname
[MAXPATHLEN
+1];
2223 char mac_pathname
[MAXPATHLEN
+1];
2225 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
2228 if (!posix_to_mac_pathname (true_pathname
, mac_pathname
, MAXPATHLEN
+1))
2233 int result
= creat (mac_pathname
);
2234 fsetfileinfo (mac_pathname
, MAC_EMACS_CREATOR_CODE
, 'TEXT');
2236 #else /* not __MRC__ */
2237 return creat (mac_pathname
, mode
);
2238 #endif /* not __MRC__ */
2245 sys_unlink (const char *path
)
2247 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
2249 char mac_pathname
[MAXPATHLEN
+1];
2251 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
2254 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
2256 fully_resolved_name
[len
] = '\0';
2258 strcpy (fully_resolved_name
, true_pathname
);
2260 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
2263 return unlink (mac_pathname
);
2269 sys_read (int fildes
, char *buf
, int count
)
2271 if (fildes
== 0) /* this should not be used for console input */
2274 #if __MSL__ >= 0x6000
2275 return _read (fildes
, buf
, count
);
2277 return read (fildes
, buf
, count
);
2284 sys_write (int fildes
, const char *buf
, int count
)
2286 if (fildes
== DEV_NULL_FD
)
2289 #if __MSL__ >= 0x6000
2290 return _write (fildes
, buf
, count
);
2292 return write (fildes
, buf
, count
);
2299 sys_rename (const char * old_name
, const char * new_name
)
2301 char true_old_pathname
[MAXPATHLEN
+1], true_new_pathname
[MAXPATHLEN
+1];
2302 char fully_resolved_old_name
[MAXPATHLEN
+1];
2304 char mac_old_name
[MAXPATHLEN
+1], mac_new_name
[MAXPATHLEN
+1];
2306 if (find_true_pathname (old_name
, true_old_pathname
, MAXPATHLEN
+1) == -1)
2309 len
= readlink (true_old_pathname
, fully_resolved_old_name
, MAXPATHLEN
);
2311 fully_resolved_old_name
[len
] = '\0';
2313 strcpy (fully_resolved_old_name
, true_old_pathname
);
2315 if (find_true_pathname (new_name
, true_new_pathname
, MAXPATHLEN
+1) == -1)
2318 if (strcmp (fully_resolved_old_name
, true_new_pathname
) == 0)
2321 if (!posix_to_mac_pathname (fully_resolved_old_name
,
2326 if (!posix_to_mac_pathname(true_new_pathname
, mac_new_name
, MAXPATHLEN
+1))
2329 /* If a file with new_name already exists, rename deletes the old
2330 file in Unix. CW version fails in these situation. So we add a
2331 call to unlink here. */
2332 (void) unlink (mac_new_name
);
2334 return rename (mac_old_name
, mac_new_name
);
2339 extern FILE *fopen (const char *name
, const char *mode
);
2341 sys_fopen (const char *name
, const char *mode
)
2343 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
2345 char mac_pathname
[MAXPATHLEN
+1];
2347 if (find_true_pathname (name
, true_pathname
, MAXPATHLEN
+1) == -1)
2350 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
2352 fully_resolved_name
[len
] = '\0';
2354 strcpy (fully_resolved_name
, true_pathname
);
2356 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
2361 if (mode
[0] == 'w' || mode
[0] == 'a')
2362 fsetfileinfo (mac_pathname
, MAC_EMACS_CREATOR_CODE
, 'TEXT');
2363 #endif /* not __MRC__ */
2364 return fopen (mac_pathname
, mode
);
2369 extern Boolean mac_wait_next_event
P_ ((EventRecord
*, UInt32
, Boolean
));
2372 select (nfds
, rfds
, wfds
, efds
, timeout
)
2374 SELECT_TYPE
*rfds
, *wfds
, *efds
;
2375 EMACS_TIME
*timeout
;
2377 OSStatus err
= noErr
;
2379 /* Can only handle wait for keyboard input. */
2380 if (nfds
> 1 || wfds
|| efds
)
2383 /* Try detect_input_pending before ReceiveNextEvent in the same
2384 BLOCK_INPUT block, in case that some input has already been read
2387 ENABLE_WAKEUP_FROM_RNE
;
2388 if (!detect_input_pending ())
2390 #if TARGET_API_MAC_CARBON
2391 EventTimeout timeoutval
=
2393 ? (EMACS_SECS (*timeout
) * kEventDurationSecond
2394 + EMACS_USECS (*timeout
) * kEventDurationMicrosecond
)
2395 : kEventDurationForever
);
2397 if (timeoutval
== 0.0)
2398 err
= eventLoopTimedOutErr
;
2400 err
= ReceiveNextEvent (0, NULL
, timeoutval
,
2401 kEventLeaveInQueue
, NULL
);
2402 #else /* not TARGET_API_MAC_CARBON */
2404 UInt32 sleep_time
= EMACS_SECS (*timeout
) * 60 +
2405 ((EMACS_USECS (*timeout
) * 60) / 1000000);
2407 if (sleep_time
== 0)
2408 err
= -9875; /* eventLoopTimedOutErr */
2411 if (mac_wait_next_event (&e
, sleep_time
, false))
2414 err
= -9875; /* eventLoopTimedOutErr */
2416 #endif /* not TARGET_API_MAC_CARBON */
2418 DISABLE_WAKEUP_FROM_RNE
;
2423 /* Pretend that `select' is interrupted by a signal. */
2424 detect_input_pending ();
2437 /* Simulation of SIGALRM. The stub for function signal stores the
2438 signal handler function in alarm_signal_func if a SIGALRM is
2442 #include "syssignal.h"
2444 static TMTask mac_atimer_task
;
2446 static QElemPtr mac_atimer_qlink
= (QElemPtr
) &mac_atimer_task
;
2448 static int signal_mask
= 0;
2451 __sigfun alarm_signal_func
= (__sigfun
) 0;
2453 __signal_func_ptr alarm_signal_func
= (__signal_func_ptr
) 0;
2454 #else /* not __MRC__ and not __MWERKS__ */
2456 #endif /* not __MRC__ and not __MWERKS__ */
2460 extern __sigfun
signal (int signal
, __sigfun signal_func
);
2462 sys_signal (int signal_num
, __sigfun signal_func
)
2464 extern __signal_func_ptr
signal (int signal
, __signal_func_ptr signal_func
);
2466 sys_signal (int signal_num
, __signal_func_ptr signal_func
)
2467 #else /* not __MRC__ and not __MWERKS__ */
2469 #endif /* not __MRC__ and not __MWERKS__ */
2471 if (signal_num
!= SIGALRM
)
2472 return signal (signal_num
, signal_func
);
2476 __sigfun old_signal_func
;
2478 __signal_func_ptr old_signal_func
;
2482 old_signal_func
= alarm_signal_func
;
2483 alarm_signal_func
= signal_func
;
2484 return old_signal_func
;
2490 mac_atimer_handler (qlink
)
2493 if (alarm_signal_func
)
2494 (alarm_signal_func
) (SIGALRM
);
2499 set_mac_atimer (count
)
2502 static TimerUPP mac_atimer_handlerUPP
= NULL
;
2504 if (mac_atimer_handlerUPP
== NULL
)
2505 mac_atimer_handlerUPP
= NewTimerUPP (mac_atimer_handler
);
2506 mac_atimer_task
.tmCount
= 0;
2507 mac_atimer_task
.tmAddr
= mac_atimer_handlerUPP
;
2508 mac_atimer_qlink
= (QElemPtr
) &mac_atimer_task
;
2509 InsTime (mac_atimer_qlink
);
2511 PrimeTime (mac_atimer_qlink
, count
);
2516 remove_mac_atimer (remaining_count
)
2517 long *remaining_count
;
2519 if (mac_atimer_qlink
)
2521 RmvTime (mac_atimer_qlink
);
2522 if (remaining_count
)
2523 *remaining_count
= mac_atimer_task
.tmCount
;
2524 mac_atimer_qlink
= NULL
;
2536 int old_mask
= signal_mask
;
2538 signal_mask
|= mask
;
2540 if ((old_mask
^ signal_mask
) & sigmask (SIGALRM
))
2541 remove_mac_atimer (NULL
);
2548 sigsetmask (int mask
)
2550 int old_mask
= signal_mask
;
2554 if ((old_mask
^ signal_mask
) & sigmask (SIGALRM
))
2555 if (signal_mask
& sigmask (SIGALRM
))
2556 remove_mac_atimer (NULL
);
2558 set_mac_atimer (mac_atimer_task
.tmCount
);
2567 long remaining_count
;
2569 if (remove_mac_atimer (&remaining_count
) == 0)
2571 set_mac_atimer (seconds
* 1000);
2573 return remaining_count
/ 1000;
2577 mac_atimer_task
.tmCount
= seconds
* 1000;
2585 setitimer (which
, value
, ovalue
)
2587 const struct itimerval
*value
;
2588 struct itimerval
*ovalue
;
2590 long remaining_count
;
2591 long count
= (EMACS_SECS (value
->it_value
) * 1000
2592 + (EMACS_USECS (value
->it_value
) + 999) / 1000);
2594 if (remove_mac_atimer (&remaining_count
) == 0)
2598 bzero (ovalue
, sizeof (*ovalue
));
2599 EMACS_SET_SECS_USECS (ovalue
->it_value
, remaining_count
/ 1000,
2600 (remaining_count
% 1000) * 1000);
2602 set_mac_atimer (count
);
2605 mac_atimer_task
.tmCount
= count
;
2611 /* gettimeofday should return the amount of time (in a timeval
2612 structure) since midnight today. The toolbox function Microseconds
2613 returns the number of microseconds (in a UnsignedWide value) since
2614 the machine was booted. Also making this complicated is WideAdd,
2615 WideSubtract, etc. take wide values. */
2622 static wide wall_clock_at_epoch
, clicks_at_epoch
;
2623 UnsignedWide uw_microseconds
;
2624 wide w_microseconds
;
2625 time_t sys_time (time_t *);
2627 /* If this function is called for the first time, record the number
2628 of seconds since midnight and the number of microseconds since
2629 boot at the time of this first call. */
2634 systime
= sys_time (NULL
);
2635 /* Store microseconds since midnight in wall_clock_at_epoch. */
2636 WideMultiply (systime
, 1000000L, &wall_clock_at_epoch
);
2637 Microseconds (&uw_microseconds
);
2638 /* Store microseconds since boot in clicks_at_epoch. */
2639 clicks_at_epoch
.hi
= uw_microseconds
.hi
;
2640 clicks_at_epoch
.lo
= uw_microseconds
.lo
;
2643 /* Get time since boot */
2644 Microseconds (&uw_microseconds
);
2646 /* Convert to time since midnight*/
2647 w_microseconds
.hi
= uw_microseconds
.hi
;
2648 w_microseconds
.lo
= uw_microseconds
.lo
;
2649 WideSubtract (&w_microseconds
, &clicks_at_epoch
);
2650 WideAdd (&w_microseconds
, &wall_clock_at_epoch
);
2651 tp
->tv_sec
= WideDivide (&w_microseconds
, 1000000L, &tp
->tv_usec
);
2659 sleep (unsigned int seconds
)
2661 unsigned long time_up
;
2664 time_up
= TickCount () + seconds
* 60;
2665 while (TickCount () < time_up
)
2667 /* Accept no event; just wait. by T.I. */
2668 WaitNextEvent (0, &e
, 30, NULL
);
2673 #endif /* __MRC__ */
2676 /* The time functions adjust time values according to the difference
2677 between the Unix and CW epoches. */
2680 extern struct tm
*gmtime (const time_t *);
2682 sys_gmtime (const time_t *timer
)
2684 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
2686 return gmtime (&unix_time
);
2691 extern struct tm
*localtime (const time_t *);
2693 sys_localtime (const time_t *timer
)
2695 #if __MSL__ >= 0x6000
2696 time_t unix_time
= *timer
;
2698 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
2701 return localtime (&unix_time
);
2706 extern char *ctime (const time_t *);
2708 sys_ctime (const time_t *timer
)
2710 #if __MSL__ >= 0x6000
2711 time_t unix_time
= *timer
;
2713 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
2716 return ctime (&unix_time
);
2721 extern time_t time (time_t *);
2723 sys_time (time_t *timer
)
2725 #if __MSL__ >= 0x6000
2726 time_t mac_time
= time (NULL
);
2728 time_t mac_time
= time (NULL
) - CW_OR_MPW_UNIX_EPOCH_DIFF
;
2738 /* no subprocesses, empty wait */
2748 croak (char *badfunc
)
2750 printf ("%s not yet implemented\r\n", badfunc
);
2756 mktemp (char *template)
2761 len
= strlen (template);
2763 while (k
>= 0 && template[k
] == 'X')
2766 k
++; /* make k index of first 'X' */
2770 /* Zero filled, number of digits equal to the number of X's. */
2771 sprintf (&template[k
], "%0*d", len
-k
, seqnum
++);
2780 /* Emulate getpwuid, getpwnam and others. */
2782 #define PASSWD_FIELD_SIZE 256
2784 static char my_passwd_name
[PASSWD_FIELD_SIZE
];
2785 static char my_passwd_dir
[MAXPATHLEN
+1];
2787 static struct passwd my_passwd
=
2793 static struct group my_group
=
2795 /* There are no groups on the mac, so we just return "root" as the
2801 /* Initialized by main () in macterm.c to pathname of emacs directory. */
2803 char emacs_passwd_dir
[MAXPATHLEN
+1];
2809 init_emacs_passwd_dir ()
2813 if (getwd (emacs_passwd_dir
) && getwd (my_passwd_dir
))
2815 /* Need pathname of first ancestor that begins with "emacs"
2816 since Mac emacs application is somewhere in the emacs-*
2818 int len
= strlen (emacs_passwd_dir
);
2820 /* j points to the "/" following the directory name being
2823 while (i
>= 0 && !found
)
2825 while (i
>= 0 && emacs_passwd_dir
[i
] != '/')
2827 if (emacs_passwd_dir
[i
] == '/' && i
+5 < len
)
2828 found
= (strncmp (&(emacs_passwd_dir
[i
+1]), "emacs", 5) == 0);
2830 emacs_passwd_dir
[j
+1] = '\0';
2841 /* Setting to "/" probably won't work but set it to something
2843 strcpy (emacs_passwd_dir
, "/");
2844 strcpy (my_passwd_dir
, "/");
2849 static struct passwd emacs_passwd
=
2855 static int my_passwd_inited
= 0;
2863 /* Note: my_passwd_dir initialized in int_emacs_passwd_dir to
2864 directory where Emacs was started. */
2866 owner_name
= (char **) GetResource ('STR ',-16096);
2870 BlockMove ((unsigned char *) *owner_name
,
2871 (unsigned char *) my_passwd_name
,
2873 HUnlock (owner_name
);
2874 p2cstr ((unsigned char *) my_passwd_name
);
2877 my_passwd_name
[0] = 0;
2882 getpwuid (uid_t uid
)
2884 if (!my_passwd_inited
)
2887 my_passwd_inited
= 1;
2895 getgrgid (gid_t gid
)
2902 getpwnam (const char *name
)
2904 if (strcmp (name
, "emacs") == 0)
2905 return &emacs_passwd
;
2907 if (!my_passwd_inited
)
2910 my_passwd_inited
= 1;
2917 /* The functions fork, kill, sigsetmask, sigblock, request_sigio,
2918 setpgrp, setpriority, and unrequest_sigio are defined to be empty
2939 error ("Can't spawn subshell");
2944 request_sigio (void)
2950 unrequest_sigio (void)
2965 pipe (int _fildes
[2])
2972 /* Hard and symbolic links. */
2975 symlink (const char *name1
, const char *name2
)
2983 link (const char *name1
, const char *name2
)
2989 #endif /* ! MAC_OSX */
2991 /* Determine the path name of the file specified by VREFNUM, DIRID,
2992 and NAME and place that in the buffer PATH of length
2995 path_from_vol_dir_name (char *path
, int man_path_len
, short vol_ref_num
,
2996 long dir_id
, ConstStr255Param name
)
3002 if (strlen (name
) > man_path_len
)
3005 memcpy (dir_name
, name
, name
[0]+1);
3006 memcpy (path
, name
, name
[0]+1);
3009 cipb
.dirInfo
.ioDrParID
= dir_id
;
3010 cipb
.dirInfo
.ioNamePtr
= dir_name
;
3014 cipb
.dirInfo
.ioVRefNum
= vol_ref_num
;
3015 cipb
.dirInfo
.ioFDirIndex
= -1;
3016 cipb
.dirInfo
.ioDrDirID
= cipb
.dirInfo
.ioDrParID
;
3017 /* go up to parent each time */
3019 err
= PBGetCatInfo (&cipb
, false);
3024 if (strlen (dir_name
) + strlen (path
) + 1 >= man_path_len
)
3027 strcat (dir_name
, ":");
3028 strcat (dir_name
, path
);
3029 /* attach to front since we're going up directory tree */
3030 strcpy (path
, dir_name
);
3032 while (cipb
.dirInfo
.ioDrDirID
!= fsRtDirID
);
3033 /* stop when we see the volume's root directory */
3035 return 1; /* success */
3042 posix_pathname_to_fsspec (ufn
, fs
)
3046 Str255 mac_pathname
;
3048 if (posix_to_mac_pathname (ufn
, mac_pathname
, sizeof (mac_pathname
)) == 0)
3052 c2pstr (mac_pathname
);
3053 return FSMakeFSSpec (0, 0, mac_pathname
, fs
);
3058 fsspec_to_posix_pathname (fs
, ufn
, ufnbuflen
)
3063 char mac_pathname
[MAXPATHLEN
];
3065 if (path_from_vol_dir_name (mac_pathname
, sizeof (mac_pathname
) - 1,
3066 fs
->vRefNum
, fs
->parID
, fs
->name
)
3067 && mac_to_posix_pathname (mac_pathname
, ufn
, ufnbuflen
))
3074 readlink (const char *path
, char *buf
, int bufsiz
)
3076 char mac_sym_link_name
[MAXPATHLEN
+1];
3079 Boolean target_is_folder
, was_aliased
;
3080 Str255 directory_name
, mac_pathname
;
3083 if (posix_to_mac_pathname (path
, mac_sym_link_name
, MAXPATHLEN
+1) == 0)
3086 c2pstr (mac_sym_link_name
);
3087 err
= FSMakeFSSpec (0, 0, mac_sym_link_name
, &fsspec
);
3094 err
= ResolveAliasFile (&fsspec
, true, &target_is_folder
, &was_aliased
);
3095 if (err
!= noErr
|| !was_aliased
)
3101 if (path_from_vol_dir_name (mac_pathname
, 255, fsspec
.vRefNum
, fsspec
.parID
,
3108 if (mac_to_posix_pathname (mac_pathname
, buf
, bufsiz
) == 0)
3114 return strlen (buf
);
3118 /* Convert a path to one with aliases fully expanded. */
3121 find_true_pathname (const char *path
, char *buf
, int bufsiz
)
3123 char *q
, temp
[MAXPATHLEN
+1];
3127 if (bufsiz
<= 0 || path
== 0 || path
[0] == '\0')
3134 q
= strchr (p
+ 1, '/');
3136 q
= strchr (p
, '/');
3137 len
= 0; /* loop may not be entered, e.g., for "/" */
3142 strncat (temp
, p
, q
- p
);
3143 len
= readlink (temp
, buf
, bufsiz
);
3146 if (strlen (temp
) + 1 > bufsiz
)
3156 if (len
+ strlen (p
) + 1 >= bufsiz
)
3160 return len
+ strlen (p
);
3165 umask (mode_t numask
)
3167 static mode_t mask
= 022;
3168 mode_t oldmask
= mask
;
3175 chmod (const char *path
, mode_t mode
)
3177 /* say it always succeed for now */
3183 fchmod (int fd
, mode_t mode
)
3185 /* say it always succeed for now */
3191 fchown (int fd
, uid_t owner
, gid_t group
)
3193 /* say it always succeed for now */
3202 return fcntl (oldd
, F_DUPFD
, 0);
3204 /* current implementation of fcntl in fcntl.mac.c simply returns old
3206 return fcntl (oldd
, F_DUPFD
);
3213 /* This is from the original sysdep.c. Emulate BSD dup2. First close
3214 newd if it already exists. Then, attempt to dup oldd. If not
3215 successful, call dup2 recursively until we are, then close the
3216 unsuccessful ones. */
3219 dup2 (int oldd
, int newd
)
3230 ret
= dup2 (oldd
, newd
);
3236 /* let it fail for now */
3253 ioctl (int d
, int request
, void *argp
)
3263 if (fildes
>=0 && fildes
<= 2)
3296 #endif /* __MRC__ */
3300 #if __MSL__ < 0x6000
3308 #endif /* __MWERKS__ */
3310 #endif /* ! MAC_OSX */
3313 /* Return the path to the directory in which Emacs can create
3314 temporary files. The MacOS "temporary items" directory cannot be
3315 used because it removes the file written by a process when it
3316 exits. In that sense it's more like "/dev/null" than "/tmp" (but
3317 again not exactly). And of course Emacs needs to read back the
3318 files written by its subprocesses. So here we write the files to a
3319 directory "Emacs" in the Preferences Folder. This directory is
3320 created if it does not exist. */
3323 get_temp_dir_name ()
3325 static char *temp_dir_name
= NULL
;
3330 char unix_dir_name
[MAXPATHLEN
+1];
3333 /* Cache directory name with pointer temp_dir_name.
3334 Look for it only the first time. */
3337 err
= FindFolder (kOnSystemDisk
, kPreferencesFolderType
, kCreateFolder
,
3338 &vol_ref_num
, &dir_id
);
3342 if (!path_from_vol_dir_name (full_path
, 255, vol_ref_num
, dir_id
, "\p"))
3345 if (strlen (full_path
) + 6 <= MAXPATHLEN
)
3346 strcat (full_path
, "Emacs:");
3350 if (!mac_to_posix_pathname (full_path
, unix_dir_name
, MAXPATHLEN
+1))
3353 dir
= opendir (unix_dir_name
); /* check whether temp directory exists */
3356 else if (mkdir (unix_dir_name
, 0700) != 0) /* create it if not */
3359 temp_dir_name
= (char *) malloc (strlen (unix_dir_name
) + 1);
3360 strcpy (temp_dir_name
, unix_dir_name
);
3363 return temp_dir_name
;
3368 /* Allocate and construct an array of pointers to strings from a list
3369 of strings stored in a 'STR#' resource. The returned pointer array
3370 is stored in the style of argv and environ: if the 'STR#' resource
3371 contains numString strings, a pointer array with numString+1
3372 elements is returned in which the last entry contains a null
3373 pointer. The pointer to the pointer array is passed by pointer in
3374 parameter t. The resource ID of the 'STR#' resource is passed in
3375 parameter StringListID.
3379 get_string_list (char ***t
, short string_list_id
)
3385 h
= GetResource ('STR#', string_list_id
);
3390 num_strings
= * (short *) p
;
3392 *t
= (char **) malloc (sizeof (char *) * (num_strings
+ 1));
3393 for (i
= 0; i
< num_strings
; i
++)
3395 short length
= *p
++;
3396 (*t
)[i
] = (char *) malloc (length
+ 1);
3397 strncpy ((*t
)[i
], p
, length
);
3398 (*t
)[i
][length
] = '\0';
3401 (*t
)[num_strings
] = 0;
3406 /* Return no string in case GetResource fails. Bug fixed by
3407 Ikegami Tsutomu. Caused MPW build to crash without sym -on
3408 option (no sym -on implies -opt local). */
3409 *t
= (char **) malloc (sizeof (char *));
3416 get_path_to_system_folder ()
3422 static char system_folder_unix_name
[MAXPATHLEN
+1];
3425 err
= FindFolder (kOnSystemDisk
, kSystemFolderType
, kDontCreateFolder
,
3426 &vol_ref_num
, &dir_id
);
3430 if (!path_from_vol_dir_name (full_path
, 255, vol_ref_num
, dir_id
, "\p"))
3433 if (!mac_to_posix_pathname (full_path
, system_folder_unix_name
,
3437 return system_folder_unix_name
;
3443 #define ENVIRON_STRING_LIST_ID 128
3445 /* Get environment variable definitions from STR# resource. */
3452 get_string_list (&environ
, ENVIRON_STRING_LIST_ID
);
3458 /* Make HOME directory the one Emacs starts up in if not specified
3460 if (getenv ("HOME") == NULL
)
3462 environ
= (char **) realloc (environ
, sizeof (char *) * (i
+ 2));
3465 environ
[i
] = (char *) malloc (strlen (my_passwd_dir
) + 6);
3468 strcpy (environ
[i
], "HOME=");
3469 strcat (environ
[i
], my_passwd_dir
);
3476 /* Make HOME directory the one Emacs starts up in if not specified
3478 if (getenv ("MAIL") == NULL
)
3480 environ
= (char **) realloc (environ
, sizeof (char *) * (i
+ 2));
3483 char * path_to_system_folder
= get_path_to_system_folder ();
3484 environ
[i
] = (char *) malloc (strlen (path_to_system_folder
) + 22);
3487 strcpy (environ
[i
], "MAIL=");
3488 strcat (environ
[i
], path_to_system_folder
);
3489 strcat (environ
[i
], "Eudora Folder/In");
3497 /* Return the value of the environment variable NAME. */
3500 getenv (const char *name
)
3502 int length
= strlen(name
);
3505 for (e
= environ
; *e
!= 0; e
++)
3506 if (strncmp(*e
, name
, length
) == 0 && (*e
)[length
] == '=')
3507 return &(*e
)[length
+ 1];
3509 if (strcmp (name
, "TMPDIR") == 0)
3510 return get_temp_dir_name ();
3517 /* see Interfaces&Libraries:Interfaces:CIncludes:signal.h */
3518 char *sys_siglist
[] =
3520 "Zero is not a signal!!!",
3522 "Interactive user interrupt", /* 2 */ "?",
3523 "Floating point exception", /* 4 */ "?", "?", "?",
3524 "Illegal instruction", /* 8 */ "?", "?", "?", "?", "?", "?", "?",
3525 "Segment violation", /* 16 */ "?", "?", "?", "?", "?", "?", "?",
3526 "?", "?", "?", "?", "?", "?", "?", "?",
3530 char *sys_siglist
[] =
3532 "Zero is not a signal!!!",
3534 "Floating point exception",
3535 "Illegal instruction",
3536 "Interactive user interrupt",
3537 "Segment violation",
3540 #else /* not __MRC__ and not __MWERKS__ */
3542 #endif /* not __MRC__ and not __MWERKS__ */
3545 #include <utsname.h>
3548 uname (struct utsname
*name
)
3551 system_name
= GetString (-16413); /* IM - Resource Manager Reference */
3554 BlockMove (*system_name
, name
->nodename
, (*system_name
)[0]+1);
3555 p2cstr (name
->nodename
);
3563 /* Event class of HLE sent to subprocess. */
3564 const OSType kEmacsSubprocessSend
= 'ESND';
3566 /* Event class of HLE sent back from subprocess. */
3567 const OSType kEmacsSubprocessReply
= 'ERPY';
3571 mystrchr (char *s
, char c
)
3573 while (*s
&& *s
!= c
)
3601 mystrcpy (char *to
, char *from
)
3613 /* Start a Mac subprocess. Arguments for it is passed in argv (null
3614 terminated). The process should run with the default directory
3615 "workdir", read input from "infn", and write output and error to
3616 "outfn" and "errfn", resp. The Process Manager call
3617 LaunchApplication is used to start the subprocess. We use high
3618 level events as the mechanism to pass arguments to the subprocess
3619 and to make Emacs wait for the subprocess to terminate and pass
3620 back a result code. The bulk of the code here packs the arguments
3621 into one message to be passed together with the high level event.
3622 Emacs also sometimes starts a subprocess using a shell to perform
3623 wildcard filename expansion. Since we don't really have a shell on
3624 the Mac, this case is detected and the starting of the shell is
3625 by-passed. We really need to add code here to do filename
3626 expansion to support such functionality.
3628 We can't use this strategy in Carbon because the High Level Event
3629 APIs are not available. */
3632 run_mac_command (argv
, workdir
, infn
, outfn
, errfn
)
3633 unsigned char **argv
;
3634 const char *workdir
;
3635 const char *infn
, *outfn
, *errfn
;
3637 #if TARGET_API_MAC_CARBON
3639 #else /* not TARGET_API_MAC_CARBON */
3640 char macappname
[MAXPATHLEN
+1], macworkdir
[MAXPATHLEN
+1];
3641 char macinfn
[MAXPATHLEN
+1], macoutfn
[MAXPATHLEN
+1], macerrfn
[MAXPATHLEN
+1];
3642 int paramlen
, argc
, newargc
, j
, retries
;
3643 char **newargv
, *param
, *p
;
3646 LaunchParamBlockRec lpbr
;
3647 EventRecord send_event
, reply_event
;
3648 RgnHandle cursor_region_handle
;
3650 unsigned long ref_con
, len
;
3652 if (posix_to_mac_pathname (workdir
, macworkdir
, MAXPATHLEN
+1) == 0)
3654 if (posix_to_mac_pathname (infn
, macinfn
, MAXPATHLEN
+1) == 0)
3656 if (posix_to_mac_pathname (outfn
, macoutfn
, MAXPATHLEN
+1) == 0)
3658 if (posix_to_mac_pathname (errfn
, macerrfn
, MAXPATHLEN
+1) == 0)
3661 paramlen
= strlen (macworkdir
) + strlen (macinfn
) + strlen (macoutfn
)
3662 + strlen (macerrfn
) + 4; /* count nulls at end of strings */
3671 /* If a subprocess is invoked with a shell, we receive 3 arguments
3672 of the form: "<path to emacs bins>/sh" "-c" "<path to emacs
3673 bins>/<command> <command args>" */
3674 j
= strlen (argv
[0]);
3675 if (j
>= 3 && strcmp (argv
[0]+j
-3, "/sh") == 0
3676 && argc
== 3 && strcmp (argv
[1], "-c") == 0)
3678 char *command
, *t
, tempmacpathname
[MAXPATHLEN
+1];
3680 /* The arguments for the command in argv[2] are separated by
3681 spaces. Count them and put the count in newargc. */
3682 command
= (char *) alloca (strlen (argv
[2])+2);
3683 strcpy (command
, argv
[2]);
3684 if (command
[strlen (command
) - 1] != ' ')
3685 strcat (command
, " ");
3689 t
= mystrchr (t
, ' ');
3693 t
= mystrchr (t
+1, ' ');
3696 newargv
= (char **) alloca (sizeof (char *) * newargc
);
3699 for (j
= 0; j
< newargc
; j
++)
3701 newargv
[j
] = (char *) alloca (strlen (t
) + 1);
3702 mystrcpy (newargv
[j
], t
);
3705 paramlen
+= strlen (newargv
[j
]) + 1;
3708 if (strncmp (newargv
[0], "~emacs/", 7) == 0)
3710 if (posix_to_mac_pathname (newargv
[0], tempmacpathname
, MAXPATHLEN
+1)
3715 { /* sometimes Emacs call "sh" without a path for the command */
3717 char *t
= (char *) alloca (strlen (newargv
[0]) + 7 + 1);
3718 strcpy (t
, "~emacs/");
3719 strcat (t
, newargv
[0]);
3722 openp (Vexec_path
, build_string (newargv
[0]), Vexec_suffixes
, &path
,
3723 make_number (X_OK
));
3727 if (posix_to_mac_pathname (SDATA (path
), tempmacpathname
,
3731 strcpy (macappname
, tempmacpathname
);
3735 if (posix_to_mac_pathname (argv
[0], macappname
, MAXPATHLEN
+1) == 0)
3738 newargv
= (char **) alloca (sizeof (char *) * argc
);
3740 for (j
= 1; j
< argc
; j
++)
3742 if (strncmp (argv
[j
], "~emacs/", 7) == 0)
3744 char *t
= strchr (argv
[j
], ' ');
3747 char tempcmdname
[MAXPATHLEN
+1], tempmaccmdname
[MAXPATHLEN
+1];
3748 strncpy (tempcmdname
, argv
[j
], t
-argv
[j
]);
3749 tempcmdname
[t
-argv
[j
]] = '\0';
3750 if (posix_to_mac_pathname (tempcmdname
, tempmaccmdname
,
3753 newargv
[j
] = (char *) alloca (strlen (tempmaccmdname
)
3755 strcpy (newargv
[j
], tempmaccmdname
);
3756 strcat (newargv
[j
], t
);
3760 char tempmaccmdname
[MAXPATHLEN
+1];
3761 if (posix_to_mac_pathname (argv
[j
], tempmaccmdname
,
3764 newargv
[j
] = (char *) alloca (strlen (tempmaccmdname
)+1);
3765 strcpy (newargv
[j
], tempmaccmdname
);
3769 newargv
[j
] = argv
[j
];
3770 paramlen
+= strlen (newargv
[j
]) + 1;
3774 /* After expanding all the arguments, we now know the length of the
3775 parameter block to be sent to the subprocess as a message
3776 attached to the HLE. */
3777 param
= (char *) malloc (paramlen
+ 1);
3783 /* first byte of message contains number of arguments for command */
3784 strcpy (p
, macworkdir
);
3785 p
+= strlen (macworkdir
);
3787 /* null terminate strings sent so it's possible to use strcpy over there */
3788 strcpy (p
, macinfn
);
3789 p
+= strlen (macinfn
);
3791 strcpy (p
, macoutfn
);
3792 p
+= strlen (macoutfn
);
3794 strcpy (p
, macerrfn
);
3795 p
+= strlen (macerrfn
);
3797 for (j
= 1; j
< newargc
; j
++)
3799 strcpy (p
, newargv
[j
]);
3800 p
+= strlen (newargv
[j
]);
3804 c2pstr (macappname
);
3806 iErr
= FSMakeFSSpec (0, 0, macappname
, &spec
);
3814 lpbr
.launchBlockID
= extendedBlock
;
3815 lpbr
.launchEPBLength
= extendedBlockLen
;
3816 lpbr
.launchControlFlags
= launchContinue
+ launchNoFileFlags
;
3817 lpbr
.launchAppSpec
= &spec
;
3818 lpbr
.launchAppParameters
= NULL
;
3820 iErr
= LaunchApplication (&lpbr
); /* call the subprocess */
3827 send_event
.what
= kHighLevelEvent
;
3828 send_event
.message
= kEmacsSubprocessSend
;
3829 /* Event ID stored in "where" unused */
3832 /* OS may think current subprocess has terminated if previous one
3833 terminated recently. */
3836 iErr
= PostHighLevelEvent (&send_event
, &lpbr
.launchProcessSN
, 0, param
,
3837 paramlen
+ 1, receiverIDisPSN
);
3839 while (iErr
== sessClosedErr
&& retries
-- > 0);
3847 cursor_region_handle
= NewRgn ();
3849 /* Wait for the subprocess to finish, when it will send us a ERPY
3850 high level event. */
3852 if (WaitNextEvent (highLevelEventMask
, &reply_event
, 180,
3853 cursor_region_handle
)
3854 && reply_event
.message
== kEmacsSubprocessReply
)
3857 /* The return code is sent through the refCon */
3858 iErr
= AcceptHighLevelEvent (&targ
, &ref_con
, NULL
, &len
);
3861 DisposeHandle ((Handle
) cursor_region_handle
);
3866 DisposeHandle ((Handle
) cursor_region_handle
);
3870 #endif /* not TARGET_API_MAC_CARBON */
3875 opendir (const char *dirname
)
3877 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
3878 char mac_pathname
[MAXPATHLEN
+1], vol_name
[MAXPATHLEN
+1];
3882 int len
, vol_name_len
;
3884 if (find_true_pathname (dirname
, true_pathname
, MAXPATHLEN
+1) == -1)
3887 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
3889 fully_resolved_name
[len
] = '\0';
3891 strcpy (fully_resolved_name
, true_pathname
);
3893 dirp
= (DIR *) malloc (sizeof(DIR));
3897 /* Handle special case when dirname is "/": sets up for readir to
3898 get all mount volumes. */
3899 if (strcmp (fully_resolved_name
, "/") == 0)
3901 dirp
->getting_volumes
= 1; /* special all mounted volumes DIR struct */
3902 dirp
->current_index
= 1; /* index for first volume */
3906 /* Handle typical cases: not accessing all mounted volumes. */
3907 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
3910 /* Emacs calls opendir without the trailing '/', Mac needs trailing ':' */
3911 len
= strlen (mac_pathname
);
3912 if (mac_pathname
[len
- 1] != ':' && len
< MAXPATHLEN
)
3913 strcat (mac_pathname
, ":");
3915 /* Extract volume name */
3916 vol_name_len
= strchr (mac_pathname
, ':') - mac_pathname
;
3917 strncpy (vol_name
, mac_pathname
, vol_name_len
);
3918 vol_name
[vol_name_len
] = '\0';
3919 strcat (vol_name
, ":");
3921 c2pstr (mac_pathname
);
3922 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
3923 /* using full pathname so vRefNum and DirID ignored */
3924 cipb
.hFileInfo
.ioVRefNum
= 0;
3925 cipb
.hFileInfo
.ioDirID
= 0;
3926 cipb
.hFileInfo
.ioFDirIndex
= 0;
3927 /* set to 0 to get information about specific dir or file */
3929 errno
= PBGetCatInfo (&cipb
, false);
3936 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x10)) /* bit 4 = 1 for directories */
3937 return 0; /* not a directory */
3939 dirp
->dir_id
= cipb
.dirInfo
.ioDrDirID
; /* used later in readdir */
3940 dirp
->getting_volumes
= 0;
3941 dirp
->current_index
= 1; /* index for first file/directory */
3944 vpb
.ioNamePtr
= vol_name
;
3945 /* using full pathname so vRefNum and DirID ignored */
3947 vpb
.ioVolIndex
= -1;
3948 errno
= PBHGetVInfo ((union HParamBlockRec
*) &vpb
, false);
3955 dirp
->vol_ref_num
= vpb
.ioVRefNum
;
3972 HParamBlockRec hpblock
;
3974 static struct dirent s_dirent
;
3975 static Str255 s_name
;
3979 /* Handle the root directory containing the mounted volumes. Call
3980 PBHGetVInfo specifying an index to obtain the info for a volume.
3981 PBHGetVInfo returns an error when it receives an index beyond the
3982 last volume, at which time we should return a nil dirent struct
3984 if (dp
->getting_volumes
)
3986 hpblock
.volumeParam
.ioNamePtr
= s_name
;
3987 hpblock
.volumeParam
.ioVRefNum
= 0;
3988 hpblock
.volumeParam
.ioVolIndex
= dp
->current_index
;
3990 errno
= PBHGetVInfo (&hpblock
, false);
3998 strcat (s_name
, "/"); /* need "/" for stat to work correctly */
4000 dp
->current_index
++;
4002 s_dirent
.d_ino
= hpblock
.volumeParam
.ioVRefNum
;
4003 s_dirent
.d_name
= s_name
;
4009 cipb
.hFileInfo
.ioVRefNum
= dp
->vol_ref_num
;
4010 cipb
.hFileInfo
.ioNamePtr
= s_name
;
4011 /* location to receive filename returned */
4013 /* return only visible files */
4017 cipb
.hFileInfo
.ioDirID
= dp
->dir_id
;
4018 /* directory ID found by opendir */
4019 cipb
.hFileInfo
.ioFDirIndex
= dp
->current_index
;
4021 errno
= PBGetCatInfo (&cipb
, false);
4028 /* insist on a visible entry */
4029 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* directory? */
4030 done
= !(cipb
.dirInfo
.ioDrUsrWds
.frFlags
& fInvisible
);
4032 done
= !(cipb
.hFileInfo
.ioFlFndrInfo
.fdFlags
& fInvisible
);
4034 dp
->current_index
++;
4047 s_dirent
.d_ino
= cipb
.dirInfo
.ioDrDirID
;
4048 /* value unimportant: non-zero for valid file */
4049 s_dirent
.d_name
= s_name
;
4059 char mac_pathname
[MAXPATHLEN
+1];
4060 Str255 directory_name
;
4064 if (path_from_vol_dir_name (mac_pathname
, 255, 0, 0, "\p") == 0)
4067 if (mac_to_posix_pathname (mac_pathname
, path
, MAXPATHLEN
+1) == 0)
4073 #endif /* ! MAC_OSX */
4077 initialize_applescript ()
4082 /* if open fails, as_scripting_component is set to NULL. Its
4083 subsequent use in OSA calls will fail with badComponentInstance
4085 as_scripting_component
= OpenDefaultComponent (kOSAComponentType
,
4086 kAppleScriptSubtype
);
4088 null_desc
.descriptorType
= typeNull
;
4089 null_desc
.dataHandle
= 0;
4090 osaerror
= OSAMakeContext (as_scripting_component
, &null_desc
,
4091 kOSANullScript
, &as_script_context
);
4093 as_script_context
= kOSANullScript
;
4094 /* use default context if create fails */
4099 terminate_applescript()
4101 OSADispose (as_scripting_component
, as_script_context
);
4102 CloseComponent (as_scripting_component
);
4105 /* Convert a lisp string to the 4 byte character code. */
4108 mac_get_code_from_arg(Lisp_Object arg
, OSType defCode
)
4117 /* check type string */
4119 if (SBYTES (arg
) != 4)
4121 error ("Wrong argument: need string of length 4 for code");
4123 result
= EndianU32_BtoN (*((UInt32
*) SDATA (arg
)));
4128 /* Convert the 4 byte character code into a 4 byte string. */
4131 mac_get_object_from_code(OSType defCode
)
4133 UInt32 code
= EndianU32_NtoB (defCode
);
4135 return make_unibyte_string ((char *)&code
, 4);
4139 DEFUN ("mac-get-file-creator", Fmac_get_file_creator
, Smac_get_file_creator
, 1, 1, 0,
4140 doc
: /* Get the creator code of FILENAME as a four character string. */)
4142 Lisp_Object filename
;
4150 Lisp_Object result
= Qnil
;
4151 CHECK_STRING (filename
);
4153 if (NILP(Ffile_exists_p(filename
)) || !NILP(Ffile_directory_p(filename
))) {
4156 filename
= Fexpand_file_name (filename
, Qnil
);
4160 status
= FSPathMakeRef(SDATA(ENCODE_FILE(filename
)), &fref
, NULL
);
4162 status
= posix_pathname_to_fsspec (SDATA (ENCODE_FILE (filename
)), &fss
);
4165 if (status
== noErr
)
4168 FSCatalogInfo catalogInfo
;
4170 status
= FSGetCatalogInfo(&fref
, kFSCatInfoFinderInfo
,
4171 &catalogInfo
, NULL
, NULL
, NULL
);
4175 status
= FSpGetFInfo (&fss
, &finder_info
);
4177 if (status
== noErr
)
4180 result
= mac_get_object_from_code(((FileInfo
*)&catalogInfo
.finderInfo
)->fileCreator
);
4182 result
= mac_get_object_from_code (finder_info
.fdCreator
);
4187 if (status
!= noErr
) {
4188 error ("Error while getting file information.");
4193 DEFUN ("mac-get-file-type", Fmac_get_file_type
, Smac_get_file_type
, 1, 1, 0,
4194 doc
: /* Get the type code of FILENAME as a four character string. */)
4196 Lisp_Object filename
;
4204 Lisp_Object result
= Qnil
;
4205 CHECK_STRING (filename
);
4207 if (NILP(Ffile_exists_p(filename
)) || !NILP(Ffile_directory_p(filename
))) {
4210 filename
= Fexpand_file_name (filename
, Qnil
);
4214 status
= FSPathMakeRef(SDATA(ENCODE_FILE(filename
)), &fref
, NULL
);
4216 status
= posix_pathname_to_fsspec (SDATA (ENCODE_FILE (filename
)), &fss
);
4219 if (status
== noErr
)
4222 FSCatalogInfo catalogInfo
;
4224 status
= FSGetCatalogInfo(&fref
, kFSCatInfoFinderInfo
,
4225 &catalogInfo
, NULL
, NULL
, NULL
);
4229 status
= FSpGetFInfo (&fss
, &finder_info
);
4231 if (status
== noErr
)
4234 result
= mac_get_object_from_code(((FileInfo
*)&catalogInfo
.finderInfo
)->fileType
);
4236 result
= mac_get_object_from_code (finder_info
.fdType
);
4241 if (status
!= noErr
) {
4242 error ("Error while getting file information.");
4247 DEFUN ("mac-set-file-creator", Fmac_set_file_creator
, Smac_set_file_creator
, 1, 2, 0,
4248 doc
: /* Set creator code of file FILENAME to CODE.
4249 If non-nil, CODE must be a 4-character string. Otherwise, 'EMAx' is
4250 assumed. Return non-nil if successful. */)
4252 Lisp_Object filename
, code
;
4261 CHECK_STRING (filename
);
4263 cCode
= mac_get_code_from_arg(code
, MAC_EMACS_CREATOR_CODE
);
4265 if (NILP(Ffile_exists_p(filename
)) || !NILP(Ffile_directory_p(filename
))) {
4268 filename
= Fexpand_file_name (filename
, Qnil
);
4272 status
= FSPathMakeRef(SDATA(ENCODE_FILE(filename
)), &fref
, NULL
);
4274 status
= posix_pathname_to_fsspec (SDATA (ENCODE_FILE (filename
)), &fss
);
4277 if (status
== noErr
)
4280 FSCatalogInfo catalogInfo
;
4282 status
= FSGetCatalogInfo(&fref
, kFSCatInfoFinderInfo
,
4283 &catalogInfo
, NULL
, NULL
, &parentDir
);
4287 status
= FSpGetFInfo (&fss
, &finder_info
);
4289 if (status
== noErr
)
4292 ((FileInfo
*)&catalogInfo
.finderInfo
)->fileCreator
= cCode
;
4293 status
= FSSetCatalogInfo(&fref
, kFSCatInfoFinderInfo
, &catalogInfo
);
4294 /* TODO: on Mac OS 10.2, we need to touch the parent dir, FNNotify? */
4296 finder_info
.fdCreator
= cCode
;
4297 status
= FSpSetFInfo (&fss
, &finder_info
);
4302 if (status
!= noErr
) {
4303 error ("Error while setting creator information.");
4308 DEFUN ("mac-set-file-type", Fmac_set_file_type
, Smac_set_file_type
, 2, 2, 0,
4309 doc
: /* Set file code of file FILENAME to CODE.
4310 CODE must be a 4-character string. Return non-nil if successful. */)
4312 Lisp_Object filename
, code
;
4321 CHECK_STRING (filename
);
4323 cCode
= mac_get_code_from_arg(code
, 0); /* Default to empty code*/
4325 if (NILP(Ffile_exists_p(filename
)) || !NILP(Ffile_directory_p(filename
))) {
4328 filename
= Fexpand_file_name (filename
, Qnil
);
4332 status
= FSPathMakeRef(SDATA(ENCODE_FILE(filename
)), &fref
, NULL
);
4334 status
= posix_pathname_to_fsspec (SDATA (ENCODE_FILE (filename
)), &fss
);
4337 if (status
== noErr
)
4340 FSCatalogInfo catalogInfo
;
4342 status
= FSGetCatalogInfo(&fref
, kFSCatInfoFinderInfo
,
4343 &catalogInfo
, NULL
, NULL
, &parentDir
);
4347 status
= FSpGetFInfo (&fss
, &finder_info
);
4349 if (status
== noErr
)
4352 ((FileInfo
*)&catalogInfo
.finderInfo
)->fileType
= cCode
;
4353 status
= FSSetCatalogInfo(&fref
, kFSCatInfoFinderInfo
, &catalogInfo
);
4354 /* TODO: on Mac OS 10.2, we need to touch the parent dir, FNNotify? */
4356 finder_info
.fdType
= cCode
;
4357 status
= FSpSetFInfo (&fss
, &finder_info
);
4362 if (status
!= noErr
) {
4363 error ("Error while setting creator information.");
4369 /* Compile and execute the AppleScript SCRIPT and return the error
4370 status as function value. A zero is returned if compilation and
4371 execution is successful, in which case *RESULT is set to a Lisp
4372 string containing the resulting script value. Otherwise, the Mac
4373 error code is returned and *RESULT is set to an error Lisp string.
4374 For documentation on the MacOS scripting architecture, see Inside
4375 Macintosh - Interapplication Communications: Scripting
4379 do_applescript (script
, result
)
4380 Lisp_Object script
, *result
;
4382 AEDesc script_desc
, result_desc
, error_desc
, *desc
= NULL
;
4388 if (!as_scripting_component
)
4389 initialize_applescript();
4391 error
= AECreateDesc (typeChar
, SDATA (script
), SBYTES (script
),
4396 osaerror
= OSADoScript (as_scripting_component
, &script_desc
, kOSANullScript
,
4397 typeChar
, kOSAModeNull
, &result_desc
);
4399 if (osaerror
== noErr
)
4400 /* success: retrieve resulting script value */
4401 desc
= &result_desc
;
4402 else if (osaerror
== errOSAScriptError
)
4403 /* error executing AppleScript: retrieve error message */
4404 if (!OSAScriptError (as_scripting_component
, kOSAErrorMessage
, typeChar
,
4410 #if TARGET_API_MAC_CARBON
4411 *result
= make_uninit_string (AEGetDescDataSize (desc
));
4412 AEGetDescData (desc
, SDATA (*result
), SBYTES (*result
));
4413 #else /* not TARGET_API_MAC_CARBON */
4414 *result
= make_uninit_string (GetHandleSize (desc
->dataHandle
));
4415 memcpy (SDATA (*result
), *(desc
->dataHandle
), SBYTES (*result
));
4416 #endif /* not TARGET_API_MAC_CARBON */
4417 AEDisposeDesc (desc
);
4420 AEDisposeDesc (&script_desc
);
4426 DEFUN ("do-applescript", Fdo_applescript
, Sdo_applescript
, 1, 1, 0,
4427 doc
: /* Compile and execute AppleScript SCRIPT and return the result.
4428 If compilation and execution are successful, the resulting script
4429 value is returned as a string. Otherwise the function aborts and
4430 displays the error message returned by the AppleScript scripting
4438 CHECK_STRING (script
);
4441 status
= do_applescript (script
, &result
);
4445 else if (!STRINGP (result
))
4446 error ("AppleScript error %d", status
);
4448 error ("%s", SDATA (result
));
4452 DEFUN ("mac-file-name-to-posix", Fmac_file_name_to_posix
,
4453 Smac_file_name_to_posix
, 1, 1, 0,
4454 doc
: /* Convert Macintosh FILENAME to Posix form. */)
4456 Lisp_Object filename
;
4458 char posix_filename
[MAXPATHLEN
+1];
4460 CHECK_STRING (filename
);
4462 if (mac_to_posix_pathname (SDATA (filename
), posix_filename
, MAXPATHLEN
))
4463 return build_string (posix_filename
);
4469 DEFUN ("posix-file-name-to-mac", Fposix_file_name_to_mac
,
4470 Sposix_file_name_to_mac
, 1, 1, 0,
4471 doc
: /* Convert Posix FILENAME to Mac form. */)
4473 Lisp_Object filename
;
4475 char mac_filename
[MAXPATHLEN
+1];
4477 CHECK_STRING (filename
);
4479 if (posix_to_mac_pathname (SDATA (filename
), mac_filename
, MAXPATHLEN
))
4480 return build_string (mac_filename
);
4486 DEFUN ("mac-coerce-ae-data", Fmac_coerce_ae_data
, Smac_coerce_ae_data
, 3, 3, 0,
4487 doc
: /* Coerce Apple event data SRC-DATA of type SRC-TYPE to DST-TYPE.
4488 Each type should be a string of length 4 or the symbol
4489 `undecoded-file-name'. */)
4490 (src_type
, src_data
, dst_type
)
4491 Lisp_Object src_type
, src_data
, dst_type
;
4494 Lisp_Object result
= Qnil
;
4495 DescType src_desc_type
, dst_desc_type
;
4498 CHECK_STRING (src_data
);
4499 if (EQ (src_type
, Qundecoded_file_name
))
4500 src_desc_type
= TYPE_FILE_NAME
;
4502 src_desc_type
= mac_get_code_from_arg (src_type
, 0);
4504 if (EQ (dst_type
, Qundecoded_file_name
))
4505 dst_desc_type
= TYPE_FILE_NAME
;
4507 dst_desc_type
= mac_get_code_from_arg (dst_type
, 0);
4510 err
= AECoercePtr (src_desc_type
, SDATA (src_data
), SBYTES (src_data
),
4511 dst_desc_type
, &dst_desc
);
4514 result
= Fcdr (mac_aedesc_to_lisp (&dst_desc
));
4515 AEDisposeDesc (&dst_desc
);
4523 #if TARGET_API_MAC_CARBON
4524 static Lisp_Object Qxml
, Qmime_charset
;
4525 static Lisp_Object QNFD
, QNFKD
, QNFC
, QNFKC
, QHFS_plus_D
, QHFS_plus_C
;
4527 DEFUN ("mac-get-preference", Fmac_get_preference
, Smac_get_preference
, 1, 4, 0,
4528 doc
: /* Return the application preference value for KEY.
4529 KEY is either a string specifying a preference key, or a list of key
4530 strings. If it is a list, the (i+1)-th element is used as a key for
4531 the CFDictionary value obtained by the i-th element. Return nil if
4532 lookup is failed at some stage.
4534 Optional arg APPLICATION is an application ID string. If omitted or
4535 nil, that stands for the current application.
4537 Optional arg FORMAT specifies the data format of the return value. If
4538 omitted or nil, each Core Foundation object is converted into a
4539 corresponding Lisp object as follows:
4541 Core Foundation Lisp Tag
4542 ------------------------------------------------------------
4543 CFString Multibyte string string
4544 CFNumber Integer or float number
4545 CFBoolean Symbol (t or nil) boolean
4546 CFDate List of three integers date
4547 (cf. `current-time')
4548 CFData Unibyte string data
4549 CFArray Vector array
4550 CFDictionary Alist or hash table dictionary
4551 (depending on HASH-BOUND)
4553 If it is t, a symbol that represents the type of the original Core
4554 Foundation object is prepended. If it is `xml', the value is returned
4555 as an XML representation.
4557 Optional arg HASH-BOUND specifies which kinds of the list objects,
4558 alists or hash tables, are used as the targets of the conversion from
4559 CFDictionary. If HASH-BOUND is a negative integer or nil, always
4560 generate alists. If HASH-BOUND >= 0, generate an alist if the number
4561 of keys in the dictionary is smaller than HASH-BOUND, and a hash table
4563 (key
, application
, format
, hash_bound
)
4564 Lisp_Object key
, application
, format
, hash_bound
;
4566 CFStringRef app_id
, key_str
;
4567 CFPropertyListRef app_plist
= NULL
, plist
;
4568 Lisp_Object result
= Qnil
, tmp
;
4569 struct gcpro gcpro1
, gcpro2
;
4572 key
= Fcons (key
, Qnil
);
4576 for (tmp
= key
; CONSP (tmp
); tmp
= XCDR (tmp
))
4577 CHECK_STRING_CAR (tmp
);
4578 CHECK_LIST_END (tmp
, key
);
4580 if (!NILP (application
))
4581 CHECK_STRING (application
);
4582 CHECK_SYMBOL (format
);
4583 if (!NILP (hash_bound
))
4584 CHECK_NUMBER (hash_bound
);
4586 GCPRO2 (key
, format
);
4590 app_id
= kCFPreferencesCurrentApplication
;
4591 if (!NILP (application
))
4593 app_id
= cfstring_create_with_string (application
);
4597 if (!CFPreferencesAppSynchronize (app_id
))
4600 key_str
= cfstring_create_with_string (XCAR (key
));
4601 if (key_str
== NULL
)
4603 app_plist
= CFPreferencesCopyAppValue (key_str
, app_id
);
4604 CFRelease (key_str
);
4605 if (app_plist
== NULL
)
4609 for (key
= XCDR (key
); CONSP (key
); key
= XCDR (key
))
4611 if (CFGetTypeID (plist
) != CFDictionaryGetTypeID ())
4613 key_str
= cfstring_create_with_string (XCAR (key
));
4614 if (key_str
== NULL
)
4616 plist
= CFDictionaryGetValue (plist
, key_str
);
4617 CFRelease (key_str
);
4624 if (EQ (format
, Qxml
))
4626 CFDataRef data
= CFPropertyListCreateXMLData (NULL
, plist
);
4629 result
= cfdata_to_lisp (data
);
4634 cfproperty_list_to_lisp (plist
, EQ (format
, Qt
),
4635 NILP (hash_bound
) ? -1 : XINT (hash_bound
));
4640 CFRelease (app_plist
);
4651 static CFStringEncoding
4652 get_cfstring_encoding_from_lisp (obj
)
4655 CFStringRef iana_name
;
4656 CFStringEncoding encoding
= kCFStringEncodingInvalidId
;
4659 return kCFStringEncodingUnicode
;
4664 if (SYMBOLP (obj
) && !NILP (Fcoding_system_p (obj
)))
4666 Lisp_Object coding_spec
, plist
;
4668 coding_spec
= Fget (obj
, Qcoding_system
);
4669 plist
= XVECTOR (coding_spec
)->contents
[3];
4670 obj
= Fplist_get (XVECTOR (coding_spec
)->contents
[3], Qmime_charset
);
4674 obj
= SYMBOL_NAME (obj
);
4678 iana_name
= cfstring_create_with_string (obj
);
4681 encoding
= CFStringConvertIANACharSetNameToEncoding (iana_name
);
4682 CFRelease (iana_name
);
4689 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
4691 cfstring_create_normalized (str
, symbol
)
4696 TextEncodingVariant variant
;
4697 float initial_mag
= 0.0;
4698 CFStringRef result
= NULL
;
4700 if (EQ (symbol
, QNFD
))
4701 form
= kCFStringNormalizationFormD
;
4702 else if (EQ (symbol
, QNFKD
))
4703 form
= kCFStringNormalizationFormKD
;
4704 else if (EQ (symbol
, QNFC
))
4705 form
= kCFStringNormalizationFormC
;
4706 else if (EQ (symbol
, QNFKC
))
4707 form
= kCFStringNormalizationFormKC
;
4708 else if (EQ (symbol
, QHFS_plus_D
))
4710 variant
= kUnicodeHFSPlusDecompVariant
;
4713 else if (EQ (symbol
, QHFS_plus_C
))
4715 variant
= kUnicodeHFSPlusCompVariant
;
4721 CFMutableStringRef mut_str
= CFStringCreateMutableCopy (NULL
, 0, str
);
4725 CFStringNormalize (mut_str
, form
);
4729 else if (initial_mag
> 0.0)
4731 UnicodeToTextInfo uni
= NULL
;
4734 UniChar
*in_text
, *buffer
= NULL
, *out_buf
= NULL
;
4735 OSStatus err
= noErr
;
4736 ByteCount out_read
, out_size
, out_len
;
4738 map
.unicodeEncoding
= CreateTextEncoding (kTextEncodingUnicodeDefault
,
4740 kTextEncodingDefaultFormat
);
4741 map
.otherEncoding
= CreateTextEncoding (kTextEncodingUnicodeDefault
,
4743 kTextEncodingDefaultFormat
);
4744 map
.mappingVersion
= kUnicodeUseLatestMapping
;
4746 length
= CFStringGetLength (str
);
4747 out_size
= (int)((float)length
* initial_mag
) * sizeof (UniChar
);
4751 in_text
= (UniChar
*)CFStringGetCharactersPtr (str
);
4752 if (in_text
== NULL
)
4754 buffer
= xmalloc (sizeof (UniChar
) * length
);
4755 CFStringGetCharacters (str
, CFRangeMake (0, length
), buffer
);
4760 err
= CreateUnicodeToTextInfo (&map
, &uni
);
4761 while (err
== noErr
)
4763 out_buf
= xmalloc (out_size
);
4764 err
= ConvertFromUnicodeToText (uni
, length
* sizeof (UniChar
),
4766 kUnicodeDefaultDirectionMask
,
4767 0, NULL
, NULL
, NULL
,
4768 out_size
, &out_read
, &out_len
,
4770 if (err
== noErr
&& out_read
< length
* sizeof (UniChar
))
4779 result
= CFStringCreateWithCharacters (NULL
, out_buf
,
4780 out_len
/ sizeof (UniChar
));
4782 DisposeUnicodeToTextInfo (&uni
);
4798 DEFUN ("mac-code-convert-string", Fmac_code_convert_string
, Smac_code_convert_string
, 3, 4, 0,
4799 doc
: /* Convert STRING from SOURCE encoding to TARGET encoding.
4800 The conversion is performed using the converter provided by the system.
4801 Each encoding is specified by either a coding system symbol, a mime
4802 charset string, or an integer as a CFStringEncoding value. An encoding
4803 of nil means UTF-16 in native byte order, no byte order mark.
4804 On Mac OS X 10.2 and later, you can do Unicode Normalization by
4805 specifying the optional argument NORMALIZATION-FORM with a symbol NFD,
4806 NFKD, NFC, NFKC, HFS+D, or HFS+C.
4807 On successful conversion, return the result string, else return nil. */)
4808 (string
, source
, target
, normalization_form
)
4809 Lisp_Object string
, source
, target
, normalization_form
;
4811 Lisp_Object result
= Qnil
;
4812 struct gcpro gcpro1
, gcpro2
, gcpro3
, gcpro4
;
4813 CFStringEncoding src_encoding
, tgt_encoding
;
4814 CFStringRef str
= NULL
;
4816 CHECK_STRING (string
);
4817 if (!INTEGERP (source
) && !STRINGP (source
))
4818 CHECK_SYMBOL (source
);
4819 if (!INTEGERP (target
) && !STRINGP (target
))
4820 CHECK_SYMBOL (target
);
4821 CHECK_SYMBOL (normalization_form
);
4823 GCPRO4 (string
, source
, target
, normalization_form
);
4827 src_encoding
= get_cfstring_encoding_from_lisp (source
);
4828 tgt_encoding
= get_cfstring_encoding_from_lisp (target
);
4830 /* We really want string_to_unibyte, but since it doesn't exist yet, we
4831 use string_as_unibyte which works as well, except for the fact that
4832 it's too permissive (it doesn't check that the multibyte string only
4833 contain single-byte chars). */
4834 string
= Fstring_as_unibyte (string
);
4835 if (src_encoding
!= kCFStringEncodingInvalidId
4836 && tgt_encoding
!= kCFStringEncodingInvalidId
)
4837 str
= CFStringCreateWithBytes (NULL
, SDATA (string
), SBYTES (string
),
4838 src_encoding
, !NILP (source
));
4839 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
4842 CFStringRef saved_str
= str
;
4844 str
= cfstring_create_normalized (saved_str
, normalization_form
);
4845 CFRelease (saved_str
);
4850 CFIndex str_len
, buf_len
;
4852 str_len
= CFStringGetLength (str
);
4853 if (CFStringGetBytes (str
, CFRangeMake (0, str_len
), tgt_encoding
, 0,
4854 !NILP (target
), NULL
, 0, &buf_len
) == str_len
)
4856 result
= make_uninit_string (buf_len
);
4857 CFStringGetBytes (str
, CFRangeMake (0, str_len
), tgt_encoding
, 0,
4858 !NILP (target
), SDATA (result
), buf_len
, NULL
);
4870 DEFUN ("mac-process-hi-command", Fmac_process_hi_command
, Smac_process_hi_command
, 1, 1, 0,
4871 doc
: /* Send a HI command whose ID is COMMAND-ID to the command chain.
4872 COMMAND-ID must be a 4-character string. Some common command IDs are
4873 defined in the Carbon Event Manager. */)
4875 Lisp_Object command_id
;
4880 bzero (&command
, sizeof (HICommand
));
4881 command
.commandID
= mac_get_code_from_arg (command_id
, 0);
4884 err
= ProcessHICommand (&command
);
4888 error ("HI command (command ID: '%s') not handled.", SDATA (command_id
));
4893 #endif /* TARGET_API_MAC_CARBON */
4897 mac_get_system_locale ()
4905 lang
= GetScriptVariable (smSystemScript
, smScriptLang
);
4906 region
= GetScriptManagerVariable (smRegionCode
);
4907 err
= LocaleRefFromLangOrRegionCode (lang
, region
, &locale
);
4909 err
= LocaleRefGetPartString (locale
, kLocaleAllPartsMask
,
4912 return build_string (str
);
4920 extern int inhibit_window_system
;
4921 extern int noninteractive
;
4923 /* Unlike in X11, window events in Carbon do not come from sockets.
4924 So we cannot simply use `select' to monitor two kinds of inputs:
4925 window events and process outputs. We emulate such functionality
4926 by regarding fd 0 as the window event channel and simultaneously
4927 monitoring both kinds of input channels. It is implemented by
4928 dividing into some cases:
4929 1. The window event channel is not involved.
4931 2. Sockets are not involved.
4932 -> Use ReceiveNextEvent.
4933 3. [If SELECT_USE_CFSOCKET is set]
4934 Only the window event channel and socket read/write channels are
4935 involved, and timeout is not too short (greater than
4936 SELECT_TIMEOUT_THRESHOLD_RUNLOOP seconds).
4937 -> Create CFSocket for each socket and add it into the current
4938 event RunLoop so that the current event loop gets quit when
4939 the socket becomes ready. Then mac_run_loop_run_once can
4940 wait for both kinds of inputs.
4942 -> Periodically poll the window input channel while repeatedly
4943 executing `select' with a short timeout
4944 (SELECT_POLLING_PERIOD_USEC microseconds). */
4946 #ifndef SELECT_USE_CFSOCKET
4947 #define SELECT_USE_CFSOCKET 1
4950 #define SELECT_POLLING_PERIOD_USEC 100000
4951 #if SELECT_USE_CFSOCKET
4952 #define SELECT_TIMEOUT_THRESHOLD_RUNLOOP 0.2
4954 /* Dictionary of file descriptors vs CFSocketRef's allocated in
4956 static CFMutableDictionaryRef cfsockets_for_select
;
4958 /* Process ID of Emacs. */
4959 static pid_t mac_emacs_pid
;
4962 socket_callback (s
, type
, address
, data
, info
)
4964 CFSocketCallBackType type
;
4970 #endif /* SELECT_USE_CFSOCKET */
4973 select_and_poll_event (nfds
, rfds
, wfds
, efds
, timeout
)
4975 SELECT_TYPE
*rfds
, *wfds
, *efds
;
4976 EMACS_TIME
*timeout
;
4980 EMACS_TIME select_timeout
;
4981 EventTimeout timeoutval
=
4983 ? (EMACS_SECS (*timeout
) * kEventDurationSecond
4984 + EMACS_USECS (*timeout
) * kEventDurationMicrosecond
)
4985 : kEventDurationForever
);
4986 SELECT_TYPE orfds
, owfds
, oefds
;
4988 if (timeout
== NULL
)
4990 if (rfds
) orfds
= *rfds
;
4991 if (wfds
) owfds
= *wfds
;
4992 if (efds
) oefds
= *efds
;
4995 /* Try detect_input_pending before mac_run_loop_run_once in the same
4996 BLOCK_INPUT block, in case that some input has already been read
5001 if (detect_input_pending ())
5004 EMACS_SET_SECS_USECS (select_timeout
, 0, 0);
5005 r
= select (nfds
, rfds
, wfds
, efds
, &select_timeout
);
5009 if (timeoutval
== 0.0)
5012 timedout_p
= mac_run_loop_run_once (timeoutval
);
5014 if (timeout
== NULL
&& timedout_p
)
5016 if (rfds
) *rfds
= orfds
;
5017 if (wfds
) *wfds
= owfds
;
5018 if (efds
) *efds
= oefds
;
5027 else if (!timedout_p
)
5029 /* Pretend that `select' is interrupted by a signal. */
5030 detect_input_pending ();
5038 /* Clean up the CFSocket associated with the file descriptor FD in
5039 case the same descriptor is used in other threads later. If no
5040 CFSocket is associated with FD, then return 0 without closing FD.
5041 Otherwise, return 1 with closing FD. */
5044 mac_try_close_socket (fd
)
5047 #if SELECT_USE_CFSOCKET
5048 if (getpid () == mac_emacs_pid
&& cfsockets_for_select
)
5050 void *key
= (void *) fd
;
5051 CFSocketRef socket
=
5052 (CFSocketRef
) CFDictionaryGetValue (cfsockets_for_select
, key
);
5056 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
5057 CFOptionFlags flags
= CFSocketGetSocketFlags (socket
);
5059 if (!(flags
& kCFSocketCloseOnInvalidate
))
5060 CFSocketSetSocketFlags (socket
, flags
| kCFSocketCloseOnInvalidate
);
5063 CFSocketInvalidate (socket
);
5064 CFDictionaryRemoveValue (cfsockets_for_select
, key
);
5076 sys_select (nfds
, rfds
, wfds
, efds
, timeout
)
5078 SELECT_TYPE
*rfds
, *wfds
, *efds
;
5079 EMACS_TIME
*timeout
;
5083 EMACS_TIME select_timeout
;
5084 SELECT_TYPE orfds
, owfds
, oefds
;
5086 if (inhibit_window_system
|| noninteractive
5087 || nfds
< 1 || rfds
== NULL
|| !FD_ISSET (0, rfds
))
5088 return select (nfds
, rfds
, wfds
, efds
, timeout
);
5102 EventTimeout timeoutval
=
5104 ? (EMACS_SECS (*timeout
) * kEventDurationSecond
5105 + EMACS_USECS (*timeout
) * kEventDurationMicrosecond
)
5106 : kEventDurationForever
);
5108 FD_SET (0, rfds
); /* sentinel */
5113 while (!(FD_ISSET (nfds
, rfds
) || (wfds
&& FD_ISSET (nfds
, wfds
))));
5118 return select_and_poll_event (nfds
, rfds
, wfds
, efds
, timeout
);
5120 /* Avoid initial overhead of RunLoop setup for the case that
5121 some input is already available. */
5122 EMACS_SET_SECS_USECS (select_timeout
, 0, 0);
5123 r
= select_and_poll_event (nfds
, rfds
, wfds
, efds
, &select_timeout
);
5124 if (r
!= 0 || timeoutval
== 0.0)
5131 #if SELECT_USE_CFSOCKET
5132 if (timeoutval
> 0 && timeoutval
<= SELECT_TIMEOUT_THRESHOLD_RUNLOOP
)
5133 goto poll_periodically
;
5135 /* Try detect_input_pending before mac_run_loop_run_once in the
5136 same BLOCK_INPUT block, in case that some input has already
5137 been read asynchronously. */
5139 if (!detect_input_pending ())
5142 CFRunLoopRef runloop
=
5143 (CFRunLoopRef
) GetCFRunLoopFromEventLoop (GetCurrentEventLoop ());
5144 static CFMutableDictionaryRef sources
;
5146 if (sources
== NULL
)
5148 CFDictionaryCreateMutable (NULL
, 0, NULL
,
5149 &kCFTypeDictionaryValueCallBacks
);
5151 if (cfsockets_for_select
== NULL
)
5152 cfsockets_for_select
=
5153 CFDictionaryCreateMutable (NULL
, 0, NULL
,
5154 &kCFTypeDictionaryValueCallBacks
);
5156 for (minfd
= 1; ; minfd
++) /* nfds-1 works as a sentinel. */
5157 if (FD_ISSET (minfd
, rfds
) || (wfds
&& FD_ISSET (minfd
, wfds
)))
5160 for (fd
= minfd
; fd
< nfds
; fd
++)
5161 if (FD_ISSET (fd
, rfds
) || (wfds
&& FD_ISSET (fd
, wfds
)))
5163 void *key
= (void *) fd
;
5164 CFRunLoopSourceRef source
=
5165 (CFRunLoopSourceRef
) CFDictionaryGetValue (sources
, key
);
5167 if (source
== NULL
|| !CFRunLoopSourceIsValid (source
))
5169 CFSocketRef socket
=
5170 CFSocketCreateWithNative (NULL
, fd
,
5171 (kCFSocketReadCallBack
5172 | kCFSocketConnectCallBack
),
5173 socket_callback
, NULL
);
5177 CFDictionarySetValue (cfsockets_for_select
, key
, socket
);
5178 source
= CFSocketCreateRunLoopSource (NULL
, socket
, 0);
5182 CFDictionarySetValue (sources
, key
, source
);
5185 CFRunLoopAddSource (runloop
, source
, kCFRunLoopDefaultMode
);
5188 timedout_p
= mac_run_loop_run_once (timeoutval
);
5190 for (fd
= minfd
; fd
< nfds
; fd
++)
5191 if (FD_ISSET (fd
, rfds
) || (wfds
&& FD_ISSET (fd
, wfds
)))
5193 void *key
= (void *) fd
;
5194 CFRunLoopSourceRef source
=
5195 (CFRunLoopSourceRef
) CFDictionaryGetValue (sources
, key
);
5197 CFRunLoopRemoveSource (runloop
, source
, kCFRunLoopDefaultMode
);
5204 EMACS_SET_SECS_USECS (select_timeout
, 0, 0);
5205 return select_and_poll_event (nfds
, rfds
, wfds
, efds
,
5215 #endif /* SELECT_USE_CFSOCKET */
5220 EMACS_TIME end_time
, now
, remaining_time
;
5224 remaining_time
= *timeout
;
5225 EMACS_GET_TIME (now
);
5226 EMACS_ADD_TIME (end_time
, now
, remaining_time
);
5231 EMACS_SET_SECS_USECS (select_timeout
, 0, SELECT_POLLING_PERIOD_USEC
);
5232 if (timeout
&& EMACS_TIME_LT (remaining_time
, select_timeout
))
5233 select_timeout
= remaining_time
;
5234 r
= select_and_poll_event (nfds
, rfds
, wfds
, efds
, &select_timeout
);
5246 EMACS_GET_TIME (now
);
5247 EMACS_SUB_TIME (remaining_time
, end_time
, now
);
5250 while (!timeout
|| EMACS_TIME_LT (now
, end_time
));
5252 EMACS_SET_SECS_USECS (select_timeout
, 0, 0);
5253 return select_and_poll_event (nfds
, rfds
, wfds
, efds
, &select_timeout
);
5257 /* Set up environment variables so that Emacs can correctly find its
5258 support files when packaged as an application bundle. Directories
5259 placed in /usr/local/share/emacs/<emacs-version>/, /usr/local/bin,
5260 and /usr/local/libexec/emacs/<emacs-version>/<system-configuration>
5261 by `make install' by default can instead be placed in
5262 .../Emacs.app/Contents/Resources/ and
5263 .../Emacs.app/Contents/MacOS/. Each of these environment variables
5264 is changed only if it is not already set. Presumably if the user
5265 sets an environment variable, he will want to use files in his path
5266 instead of ones in the application bundle. */
5268 init_mac_osx_environment ()
5272 CFStringRef cf_app_bundle_pathname
;
5273 int app_bundle_pathname_len
;
5274 char *app_bundle_pathname
;
5278 mac_emacs_pid
= getpid ();
5280 /* Initialize locale related variables. */
5281 mac_system_script_code
=
5282 (ScriptCode
) GetScriptManagerVariable (smSysScript
);
5283 Vmac_system_locale
= mac_get_system_locale ();
5285 /* Fetch the pathname of the application bundle as a C string into
5286 app_bundle_pathname. */
5288 bundle
= CFBundleGetMainBundle ();
5289 if (!bundle
|| CFBundleGetIdentifier (bundle
) == NULL
)
5291 /* We could not find the bundle identifier. For now, prevent
5292 the fatal error by bringing it up in the terminal. */
5293 inhibit_window_system
= 1;
5297 bundleURL
= CFBundleCopyBundleURL (bundle
);
5301 cf_app_bundle_pathname
= CFURLCopyFileSystemPath (bundleURL
,
5302 kCFURLPOSIXPathStyle
);
5303 app_bundle_pathname_len
= CFStringGetLength (cf_app_bundle_pathname
);
5304 app_bundle_pathname
= (char *) alloca (app_bundle_pathname_len
+ 1);
5306 if (!CFStringGetCString (cf_app_bundle_pathname
,
5307 app_bundle_pathname
,
5308 app_bundle_pathname_len
+ 1,
5309 kCFStringEncodingISOLatin1
))
5311 CFRelease (cf_app_bundle_pathname
);
5315 CFRelease (cf_app_bundle_pathname
);
5317 /* P should have sufficient room for the pathname of the bundle plus
5318 the subpath in it leading to the respective directories. Q
5319 should have three times that much room because EMACSLOADPATH can
5320 have the value "<path to site-lisp dir>:<path to lisp dir>:<path
5322 p
= (char *) alloca (app_bundle_pathname_len
+ 50);
5323 q
= (char *) alloca (3 * app_bundle_pathname_len
+ 150);
5324 if (!getenv ("EMACSLOADPATH"))
5328 strcpy (p
, app_bundle_pathname
);
5329 strcat (p
, "/Contents/Resources/site-lisp");
5330 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
5333 strcpy (p
, app_bundle_pathname
);
5334 strcat (p
, "/Contents/Resources/lisp");
5335 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
5342 strcpy (p
, app_bundle_pathname
);
5343 strcat (p
, "/Contents/Resources/leim");
5344 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
5352 setenv ("EMACSLOADPATH", q
, 1);
5355 if (!getenv ("EMACSPATH"))
5359 strcpy (p
, app_bundle_pathname
);
5360 strcat (p
, "/Contents/MacOS/libexec");
5361 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
5364 strcpy (p
, app_bundle_pathname
);
5365 strcat (p
, "/Contents/MacOS/bin");
5366 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
5374 setenv ("EMACSPATH", q
, 1);
5377 if (!getenv ("EMACSDATA"))
5379 strcpy (p
, app_bundle_pathname
);
5380 strcat (p
, "/Contents/Resources/etc");
5381 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
5382 setenv ("EMACSDATA", p
, 1);
5385 if (!getenv ("EMACSDOC"))
5387 strcpy (p
, app_bundle_pathname
);
5388 strcat (p
, "/Contents/Resources/etc");
5389 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
5390 setenv ("EMACSDOC", p
, 1);
5393 if (!getenv ("INFOPATH"))
5395 strcpy (p
, app_bundle_pathname
);
5396 strcat (p
, "/Contents/Resources/info");
5397 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
5398 setenv ("INFOPATH", p
, 1);
5401 #endif /* MAC_OSX */
5403 #if TARGET_API_MAC_CARBON
5405 mac_wakeup_from_rne ()
5408 if (wakeup_from_rne_enabled_p
)
5409 /* Post a harmless event so as to wake up from
5410 ReceiveNextEvent. */
5411 mac_post_mouse_moved_event ();
5419 Qundecoded_file_name
= intern ("undecoded-file-name");
5420 staticpro (&Qundecoded_file_name
);
5422 #if TARGET_API_MAC_CARBON
5423 Qstring
= intern ("string"); staticpro (&Qstring
);
5424 Qnumber
= intern ("number"); staticpro (&Qnumber
);
5425 Qboolean
= intern ("boolean"); staticpro (&Qboolean
);
5426 Qdate
= intern ("date"); staticpro (&Qdate
);
5427 Qdata
= intern ("data"); staticpro (&Qdata
);
5428 Qarray
= intern ("array"); staticpro (&Qarray
);
5429 Qdictionary
= intern ("dictionary"); staticpro (&Qdictionary
);
5431 Qxml
= intern ("xml");
5434 Qmime_charset
= intern ("mime-charset");
5435 staticpro (&Qmime_charset
);
5437 QNFD
= intern ("NFD"); staticpro (&QNFD
);
5438 QNFKD
= intern ("NFKD"); staticpro (&QNFKD
);
5439 QNFC
= intern ("NFC"); staticpro (&QNFC
);
5440 QNFKC
= intern ("NFKC"); staticpro (&QNFKC
);
5441 QHFS_plus_D
= intern ("HFS+D"); staticpro (&QHFS_plus_D
);
5442 QHFS_plus_C
= intern ("HFS+C"); staticpro (&QHFS_plus_C
);
5448 for (i
= 0; i
< sizeof (ae_attr_table
) / sizeof (ae_attr_table
[0]); i
++)
5450 ae_attr_table
[i
].symbol
= intern (ae_attr_table
[i
].name
);
5451 staticpro (&ae_attr_table
[i
].symbol
);
5455 defsubr (&Smac_coerce_ae_data
);
5456 #if TARGET_API_MAC_CARBON
5457 defsubr (&Smac_get_preference
);
5458 defsubr (&Smac_code_convert_string
);
5459 defsubr (&Smac_process_hi_command
);
5462 defsubr (&Smac_set_file_creator
);
5463 defsubr (&Smac_set_file_type
);
5464 defsubr (&Smac_get_file_creator
);
5465 defsubr (&Smac_get_file_type
);
5466 defsubr (&Sdo_applescript
);
5467 defsubr (&Smac_file_name_to_posix
);
5468 defsubr (&Sposix_file_name_to_mac
);
5470 DEFVAR_INT ("mac-system-script-code", &mac_system_script_code
,
5471 doc
: /* The system script code. */);
5472 mac_system_script_code
= (ScriptCode
) GetScriptManagerVariable (smSysScript
);
5474 DEFVAR_LISP ("mac-system-locale", &Vmac_system_locale
,
5475 doc
: /* The system locale identifier string.
5476 This is not a POSIX locale ID, but an ICU locale ID. So encoding
5477 information is not included. */);
5478 Vmac_system_locale
= mac_get_system_locale ();
5481 /* arch-tag: 29d30c1f-0c6b-4f88-8a6d-0558d7f9dbff
5482 (do not change this comment) */