1 /* Unix emulation routines for GNU Emacs on the Mac OS.
2 Copyright (C) 2000, 2001, 2002, 2003, 2004,
3 2005, 2006, 2007 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 2, 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
;
82 #if TARGET_API_MAC_CARBON
83 static int wakeup_from_rne_enabled_p
= 0;
84 #define ENABLE_WAKEUP_FROM_RNE (wakeup_from_rne_enabled_p = 1)
85 #define DISABLE_WAKEUP_FROM_RNE (wakeup_from_rne_enabled_p = 0)
87 #define ENABLE_WAKEUP_FROM_RNE 0
88 #define DISABLE_WAKEUP_FROM_RNE 0
92 static OSErr posix_pathname_to_fsspec
P_ ((const char *, FSSpec
*));
93 static OSErr fsspec_to_posix_pathname
P_ ((const FSSpec
*, char *, int));
96 /* When converting from Mac to Unix pathnames, /'s in folder names are
97 converted to :'s. This function, used in copying folder names,
98 performs a strncat and converts all character a to b in the copy of
99 the string s2 appended to the end of s1. */
102 string_cat_and_replace (char *s1
, const char *s2
, int n
, char a
, char b
)
104 int l1
= strlen (s1
);
105 int l2
= strlen (s2
);
110 for (i
= 0; i
< l2
; i
++)
119 /* Convert a Mac pathname to Posix form. A Mac full pathname is one
120 that does not begin with a ':' and contains at least one ':'. A Mac
121 full pathname causes a '/' to be prepended to the Posix pathname.
122 The algorithm for the rest of the pathname is as follows:
123 For each segment between two ':',
124 if it is non-null, copy as is and then add a '/' at the end,
125 otherwise, insert a "../" into the Posix pathname.
126 Returns 1 if successful; 0 if fails. */
129 mac_to_posix_pathname (const char *mfn
, char *ufn
, int ufnbuflen
)
131 const char *p
, *q
, *pe
;
138 p
= strchr (mfn
, ':');
139 if (p
!= 0 && p
!= mfn
) /* full pathname */
146 pe
= mfn
+ strlen (mfn
);
153 { /* two consecutive ':' */
154 if (strlen (ufn
) + 3 >= ufnbuflen
)
160 if (strlen (ufn
) + (q
- p
) + 1 >= ufnbuflen
)
162 string_cat_and_replace (ufn
, p
, q
- p
, '/', ':');
169 if (strlen (ufn
) + (pe
- p
) >= ufnbuflen
)
171 string_cat_and_replace (ufn
, p
, pe
- p
, '/', ':');
172 /* no separator for last one */
181 extern char *get_temp_dir_name ();
184 /* Convert a Posix pathname to Mac form. Approximately reverse of the
185 above in algorithm. */
188 posix_to_mac_pathname (const char *ufn
, char *mfn
, int mfnbuflen
)
190 const char *p
, *q
, *pe
;
191 char expanded_pathname
[MAXPATHLEN
+1];
200 /* Check for and handle volume names. Last comparison: strangely
201 somewhere "/.emacs" is passed. A temporary fix for now. */
202 if (*p
== '/' && strchr (p
+1, '/') == NULL
&& strcmp (p
, "/.emacs") != 0)
204 if (strlen (p
) + 1 > mfnbuflen
)
211 /* expand to emacs dir found by init_emacs_passwd_dir */
212 if (strncmp (p
, "~emacs/", 7) == 0)
214 struct passwd
*pw
= getpwnam ("emacs");
216 if (strlen (pw
->pw_dir
) + strlen (p
) > MAXPATHLEN
)
218 strcpy (expanded_pathname
, pw
->pw_dir
);
219 strcat (expanded_pathname
, p
);
220 p
= expanded_pathname
;
221 /* now p points to the pathname with emacs dir prefix */
223 else if (strncmp (p
, "/tmp/", 5) == 0)
225 char *t
= get_temp_dir_name ();
227 if (strlen (t
) + strlen (p
) > MAXPATHLEN
)
229 strcpy (expanded_pathname
, t
);
230 strcat (expanded_pathname
, p
);
231 p
= expanded_pathname
;
232 /* now p points to the pathname with emacs dir prefix */
234 else if (*p
!= '/') /* relative pathname */
246 if (q
- p
== 2 && *p
== '.' && *(p
+1) == '.')
248 if (strlen (mfn
) + 1 >= mfnbuflen
)
254 if (strlen (mfn
) + (q
- p
) + 1 >= mfnbuflen
)
256 string_cat_and_replace (mfn
, p
, q
- p
, ':', '/');
263 if (strlen (mfn
) + (pe
- p
) >= mfnbuflen
)
265 string_cat_and_replace (mfn
, p
, pe
- p
, ':', '/');
274 /***********************************************************************
275 Conversions on Apple event objects
276 ***********************************************************************/
278 static Lisp_Object Qundecoded_file_name
;
285 {{keyTransactionIDAttr
, "transaction-id"},
286 {keyReturnIDAttr
, "return-id"},
287 {keyEventClassAttr
, "event-class"},
288 {keyEventIDAttr
, "event-id"},
289 {keyAddressAttr
, "address"},
290 {keyOptionalKeywordAttr
, "optional-keyword"},
291 {keyTimeoutAttr
, "timeout"},
292 {keyInteractLevelAttr
, "interact-level"},
293 {keyEventSourceAttr
, "event-source"},
294 /* {keyMissedKeywordAttr, "missed-keyword"}, */
295 {keyOriginalAddressAttr
, "original-address"},
296 {keyReplyRequestedAttr
, "reply-requested"},
297 {KEY_EMACS_SUSPENSION_ID_ATTR
, "emacs-suspension-id"}
301 mac_aelist_to_lisp (desc_list
)
302 const AEDescList
*desc_list
;
306 Lisp_Object result
, elem
;
313 err
= AECountItems (desc_list
, &count
);
323 keyword
= ae_attr_table
[count
- 1].keyword
;
324 err
= AESizeOfAttribute (desc_list
, keyword
, &desc_type
, &size
);
327 err
= AESizeOfNthItem (desc_list
, count
, &desc_type
, &size
);
336 err
= AEGetAttributeDesc (desc_list
, keyword
, typeWildCard
,
339 err
= AEGetNthDesc (desc_list
, count
, typeWildCard
,
343 elem
= mac_aelist_to_lisp (&desc
);
344 AEDisposeDesc (&desc
);
348 if (desc_type
== typeNull
)
352 elem
= make_uninit_string (size
);
354 err
= AEGetAttributePtr (desc_list
, keyword
, typeWildCard
,
355 &desc_type
, SDATA (elem
),
358 err
= AEGetNthPtr (desc_list
, count
, typeWildCard
, &keyword
,
359 &desc_type
, SDATA (elem
), size
, &size
);
363 desc_type
= EndianU32_NtoB (desc_type
);
364 elem
= Fcons (make_unibyte_string ((char *) &desc_type
, 4), elem
);
368 if (err
== noErr
|| desc_list
->descriptorType
== typeAEList
)
371 elem
= Qnil
; /* Don't skip elements in AEList. */
372 else if (desc_list
->descriptorType
!= typeAEList
)
375 elem
= Fcons (ae_attr_table
[count
-1].symbol
, elem
);
378 keyword
= EndianU32_NtoB (keyword
);
379 elem
= Fcons (make_unibyte_string ((char *) &keyword
, 4),
384 result
= Fcons (elem
, result
);
390 if (desc_list
->descriptorType
== typeAppleEvent
&& !attribute_p
)
393 count
= sizeof (ae_attr_table
) / sizeof (ae_attr_table
[0]);
397 desc_type
= EndianU32_NtoB (desc_list
->descriptorType
);
398 return Fcons (make_unibyte_string ((char *) &desc_type
, 4), result
);
402 mac_aedesc_to_lisp (desc
)
406 DescType desc_type
= desc
->descriptorType
;
418 return mac_aelist_to_lisp (desc
);
420 /* The following one is much simpler, but creates and disposes
421 of Apple event descriptors many times. */
428 err
= AECountItems (desc
, &count
);
434 err
= AEGetNthDesc (desc
, count
, typeWildCard
, &keyword
, &desc1
);
437 elem
= mac_aedesc_to_lisp (&desc1
);
438 AEDisposeDesc (&desc1
);
439 if (desc_type
!= typeAEList
)
441 keyword
= EndianU32_NtoB (keyword
);
442 elem
= Fcons (make_unibyte_string ((char *) &keyword
, 4), elem
);
444 result
= Fcons (elem
, result
);
452 #if TARGET_API_MAC_CARBON
453 result
= make_uninit_string (AEGetDescDataSize (desc
));
454 err
= AEGetDescData (desc
, SDATA (result
), SBYTES (result
));
456 result
= make_uninit_string (GetHandleSize (desc
->dataHandle
));
457 memcpy (SDATA (result
), *(desc
->dataHandle
), SBYTES (result
));
465 desc_type
= EndianU32_NtoB (desc_type
);
466 return Fcons (make_unibyte_string ((char *) &desc_type
, 4), result
);
470 mac_ae_put_lisp (desc
, keyword_or_index
, obj
)
472 UInt32 keyword_or_index
;
477 if (!(desc
->descriptorType
== typeAppleEvent
478 || desc
->descriptorType
== typeAERecord
479 || desc
->descriptorType
== typeAEList
))
480 return errAEWrongDataType
;
482 if (CONSP (obj
) && STRINGP (XCAR (obj
)) && SBYTES (XCAR (obj
)) == 4)
484 DescType desc_type1
= EndianU32_BtoN (*((UInt32
*) SDATA (XCAR (obj
))));
485 Lisp_Object data
= XCDR (obj
), rest
;
496 err
= AECreateList (NULL
, 0, desc_type1
== typeAERecord
, &desc1
);
499 for (rest
= data
; CONSP (rest
); rest
= XCDR (rest
))
501 UInt32 keyword_or_index1
= 0;
502 Lisp_Object elem
= XCAR (rest
);
504 if (desc_type1
== typeAERecord
)
506 if (CONSP (elem
) && STRINGP (XCAR (elem
))
507 && SBYTES (XCAR (elem
)) == 4)
510 EndianU32_BtoN (*((UInt32
*)
511 SDATA (XCAR (elem
))));
518 err
= mac_ae_put_lisp (&desc1
, keyword_or_index1
, elem
);
525 if (desc
->descriptorType
== typeAEList
)
526 err
= AEPutDesc (desc
, keyword_or_index
, &desc1
);
528 err
= AEPutParamDesc (desc
, keyword_or_index
, &desc1
);
531 AEDisposeDesc (&desc1
);
538 if (desc
->descriptorType
== typeAEList
)
539 err
= AEPutPtr (desc
, keyword_or_index
, desc_type1
,
540 SDATA (data
), SBYTES (data
));
542 err
= AEPutParamPtr (desc
, keyword_or_index
, desc_type1
,
543 SDATA (data
), SBYTES (data
));
548 if (desc
->descriptorType
== typeAEList
)
549 err
= AEPutPtr (desc
, keyword_or_index
, typeNull
, NULL
, 0);
551 err
= AEPutParamPtr (desc
, keyword_or_index
, typeNull
, NULL
, 0);
557 mac_coerce_file_name_ptr (type_code
, data_ptr
, data_size
,
558 to_type
, handler_refcon
, result
)
560 const void *data_ptr
;
568 if (type_code
== typeNull
)
569 err
= errAECoercionFail
;
570 else if (type_code
== to_type
|| to_type
== typeWildCard
)
571 err
= AECreateDesc (TYPE_FILE_NAME
, data_ptr
, data_size
, result
);
572 else if (type_code
== TYPE_FILE_NAME
)
573 /* Coercion from undecoded file name. */
578 CFDataRef data
= NULL
;
580 str
= CFStringCreateWithBytes (NULL
, data_ptr
, data_size
,
581 kCFStringEncodingUTF8
, false);
584 url
= CFURLCreateWithFileSystemPath (NULL
, str
,
585 kCFURLPOSIXPathStyle
, false);
590 data
= CFURLCreateData (NULL
, url
, kCFStringEncodingUTF8
, true);
595 err
= AECoercePtr (typeFileURL
, CFDataGetBytePtr (data
),
596 CFDataGetLength (data
), to_type
, result
);
604 /* Just to be paranoid ... */
608 buf
= xmalloc (data_size
+ 1);
609 memcpy (buf
, data_ptr
, data_size
);
610 buf
[data_size
] = '\0';
611 err
= FSPathMakeRef (buf
, &fref
, NULL
);
614 err
= AECoercePtr (typeFSRef
, &fref
, sizeof (FSRef
),
621 buf
= xmalloc (data_size
+ 1);
622 memcpy (buf
, data_ptr
, data_size
);
623 buf
[data_size
] = '\0';
624 err
= posix_pathname_to_fsspec (buf
, &fs
);
627 err
= AECoercePtr (typeFSS
, &fs
, sizeof (FSSpec
), to_type
, result
);
630 else if (to_type
== TYPE_FILE_NAME
)
631 /* Coercion to undecoded file name. */
635 CFStringRef str
= NULL
;
636 CFDataRef data
= NULL
;
638 if (type_code
== typeFileURL
)
639 url
= CFURLCreateWithBytes (NULL
, data_ptr
, data_size
,
640 kCFStringEncodingUTF8
, NULL
);
647 err
= AECoercePtr (type_code
, data_ptr
, data_size
,
651 size
= AEGetDescDataSize (&desc
);
652 buf
= xmalloc (size
);
653 err
= AEGetDescData (&desc
, buf
, size
);
655 url
= CFURLCreateWithBytes (NULL
, buf
, size
,
656 kCFStringEncodingUTF8
, NULL
);
658 AEDisposeDesc (&desc
);
663 str
= CFURLCopyFileSystemPath (url
, kCFURLPOSIXPathStyle
);
668 data
= CFStringCreateExternalRepresentation (NULL
, str
,
669 kCFStringEncodingUTF8
,
675 err
= AECreateDesc (TYPE_FILE_NAME
, CFDataGetBytePtr (data
),
676 CFDataGetLength (data
), result
);
682 /* Coercion from typeAlias to typeFileURL fails on Mac OS X
683 10.2. In such cases, try typeFSRef as a target type. */
684 char file_name
[MAXPATHLEN
];
686 if (type_code
== typeFSRef
&& data_size
== sizeof (FSRef
))
687 err
= FSRefMakePath (data_ptr
, file_name
, sizeof (file_name
));
693 err
= AECoercePtr (type_code
, data_ptr
, data_size
,
697 err
= AEGetDescData (&desc
, &fref
, sizeof (FSRef
));
698 AEDisposeDesc (&desc
);
701 err
= FSRefMakePath (&fref
, file_name
, sizeof (file_name
));
704 err
= AECreateDesc (TYPE_FILE_NAME
, file_name
,
705 strlen (file_name
), result
);
708 char file_name
[MAXPATHLEN
];
710 if (type_code
== typeFSS
&& data_size
== sizeof (FSSpec
))
711 err
= fsspec_to_posix_pathname (data_ptr
, file_name
,
712 sizeof (file_name
) - 1);
718 err
= AECoercePtr (type_code
, data_ptr
, data_size
, typeFSS
, &desc
);
721 #if TARGET_API_MAC_CARBON
722 err
= AEGetDescData (&desc
, &fs
, sizeof (FSSpec
));
724 fs
= *(FSSpec
*)(*(desc
.dataHandle
));
726 AEDisposeDesc (&desc
);
729 err
= fsspec_to_posix_pathname (&fs
, file_name
,
730 sizeof (file_name
) - 1);
733 err
= AECreateDesc (TYPE_FILE_NAME
, file_name
,
734 strlen (file_name
), result
);
741 return errAECoercionFail
;
746 mac_coerce_file_name_desc (from_desc
, to_type
, handler_refcon
, result
)
747 const AEDesc
*from_desc
;
753 DescType from_type
= from_desc
->descriptorType
;
755 if (from_type
== typeNull
)
756 err
= errAECoercionFail
;
757 else if (from_type
== to_type
|| to_type
== typeWildCard
)
758 err
= AEDuplicateDesc (from_desc
, result
);
764 #if TARGET_API_MAC_CARBON
765 data_size
= AEGetDescDataSize (from_desc
);
767 data_size
= GetHandleSize (from_desc
->dataHandle
);
769 data_ptr
= xmalloc (data_size
);
770 #if TARGET_API_MAC_CARBON
771 err
= AEGetDescData (from_desc
, data_ptr
, data_size
);
773 memcpy (data_ptr
, *(from_desc
->dataHandle
), data_size
);
776 err
= mac_coerce_file_name_ptr (from_type
, data_ptr
,
778 handler_refcon
, result
);
783 return errAECoercionFail
;
788 init_coercion_handler ()
792 static AECoercePtrUPP coerce_file_name_ptrUPP
= NULL
;
793 static AECoerceDescUPP coerce_file_name_descUPP
= NULL
;
795 if (coerce_file_name_ptrUPP
== NULL
)
797 coerce_file_name_ptrUPP
= NewAECoercePtrUPP (mac_coerce_file_name_ptr
);
798 coerce_file_name_descUPP
= NewAECoerceDescUPP (mac_coerce_file_name_desc
);
801 err
= AEInstallCoercionHandler (TYPE_FILE_NAME
, typeWildCard
,
802 (AECoercionHandlerUPP
)
803 coerce_file_name_ptrUPP
, 0, false, false);
805 err
= AEInstallCoercionHandler (typeWildCard
, TYPE_FILE_NAME
,
806 (AECoercionHandlerUPP
)
807 coerce_file_name_ptrUPP
, 0, false, false);
809 err
= AEInstallCoercionHandler (TYPE_FILE_NAME
, typeWildCard
,
810 coerce_file_name_descUPP
, 0, true, false);
812 err
= AEInstallCoercionHandler (typeWildCard
, TYPE_FILE_NAME
,
813 coerce_file_name_descUPP
, 0, true, false);
817 #if TARGET_API_MAC_CARBON
819 create_apple_event (class, id
, result
)
825 static const ProcessSerialNumber psn
= {0, kCurrentProcess
};
826 AEAddressDesc address_desc
;
828 err
= AECreateDesc (typeProcessSerialNumber
, &psn
,
829 sizeof (ProcessSerialNumber
), &address_desc
);
832 err
= AECreateAppleEvent (class, id
,
833 &address_desc
, /* NULL is not allowed
834 on Mac OS Classic. */
835 kAutoGenerateReturnID
,
836 kAnyTransactionID
, result
);
837 AEDisposeDesc (&address_desc
);
844 create_apple_event_from_event_ref (event
, num_params
, names
, types
, result
)
847 const EventParamName
*names
;
848 const EventParamType
*types
;
857 err
= create_apple_event (0, 0, result
); /* Dummy class and ID. */
861 for (i
= 0; i
< num_params
; i
++)
865 case typeCFStringRef
:
866 err
= GetEventParameter (event
, names
[i
], typeCFStringRef
, NULL
,
867 sizeof (CFStringRef
), NULL
, &string
);
870 data
= CFStringCreateExternalRepresentation (NULL
, string
,
871 kCFStringEncodingUTF8
,
875 AEPutParamPtr (result
, names
[i
], typeUTF8Text
,
876 CFDataGetBytePtr (data
), CFDataGetLength (data
));
882 err
= GetEventParameter (event
, names
[i
], types
[i
], NULL
,
886 buf
= xrealloc (buf
, size
);
887 err
= GetEventParameter (event
, names
[i
], types
[i
], NULL
,
890 AEPutParamPtr (result
, names
[i
], types
[i
], buf
, size
);
900 create_apple_event_from_drag_ref (drag
, num_types
, types
, result
)
903 const FlavorType
*types
;
912 err
= CountDragItems (drag
, &num_items
);
915 err
= AECreateList (NULL
, 0, false, &items
);
919 for (index
= 1; index
<= num_items
; index
++)
922 DescType desc_type
= typeNull
;
925 err
= GetDragItemReferenceNumber (drag
, index
, &item
);
930 for (i
= 0; i
< num_types
; i
++)
932 err
= GetFlavorDataSize (drag
, item
, types
[i
], &size
);
935 buf
= xrealloc (buf
, size
);
936 err
= GetFlavorData (drag
, item
, types
[i
], buf
, &size
, 0);
940 desc_type
= types
[i
];
945 err
= AEPutPtr (&items
, index
, desc_type
,
946 desc_type
!= typeNull
? buf
: NULL
,
947 desc_type
!= typeNull
? size
: 0);
956 err
= create_apple_event (0, 0, result
); /* Dummy class and ID. */
958 err
= AEPutParamDesc (result
, keyDirectObject
, &items
);
960 AEDisposeDesc (result
);
963 AEDisposeDesc (&items
);
967 #endif /* TARGET_API_MAC_CARBON */
969 /***********************************************************************
970 Conversion between Lisp and Core Foundation objects
971 ***********************************************************************/
973 #if TARGET_API_MAC_CARBON
974 static Lisp_Object Qstring
, Qnumber
, Qboolean
, Qdate
, Qdata
;
975 static Lisp_Object Qarray
, Qdictionary
;
977 struct cfdict_context
980 int with_tag
, hash_bound
;
983 /* C string to CFString. */
986 cfstring_create_with_utf8_cstring (c_str
)
991 str
= CFStringCreateWithCString (NULL
, c_str
, kCFStringEncodingUTF8
);
993 /* Failed to interpret as UTF 8. Fall back on Mac Roman. */
994 str
= CFStringCreateWithCString (NULL
, c_str
, kCFStringEncodingMacRoman
);
1000 /* Lisp string to CFString. */
1003 cfstring_create_with_string (s
)
1006 CFStringRef string
= NULL
;
1008 if (STRING_MULTIBYTE (s
))
1010 char *p
, *end
= SDATA (s
) + SBYTES (s
);
1012 for (p
= SDATA (s
); p
< end
; p
++)
1015 s
= ENCODE_UTF_8 (s
);
1018 string
= CFStringCreateWithBytes (NULL
, SDATA (s
), SBYTES (s
),
1019 kCFStringEncodingUTF8
, false);
1023 /* Failed to interpret as UTF 8. Fall back on Mac Roman. */
1024 string
= CFStringCreateWithBytes (NULL
, SDATA (s
), SBYTES (s
),
1025 kCFStringEncodingMacRoman
, false);
1031 /* From CFData to a lisp string. Always returns a unibyte string. */
1034 cfdata_to_lisp (data
)
1037 CFIndex len
= CFDataGetLength (data
);
1038 Lisp_Object result
= make_uninit_string (len
);
1040 CFDataGetBytes (data
, CFRangeMake (0, len
), SDATA (result
));
1046 /* From CFString to a lisp string. Returns a unibyte string
1047 containing a UTF-8 byte sequence. */
1050 cfstring_to_lisp_nodecode (string
)
1053 Lisp_Object result
= Qnil
;
1054 const char *s
= CFStringGetCStringPtr (string
, kCFStringEncodingUTF8
);
1057 result
= make_unibyte_string (s
, strlen (s
));
1061 CFStringCreateExternalRepresentation (NULL
, string
,
1062 kCFStringEncodingUTF8
, '?');
1066 result
= cfdata_to_lisp (data
);
1075 /* From CFString to a lisp string. Never returns a unibyte string
1076 (even if it only contains ASCII characters).
1077 This may cause GC during code conversion. */
1080 cfstring_to_lisp (string
)
1083 Lisp_Object result
= cfstring_to_lisp_nodecode (string
);
1087 result
= code_convert_string_norecord (result
, Qutf_8
, 0);
1088 /* This may be superfluous. Just to make sure that the result
1089 is a multibyte string. */
1090 result
= string_to_multibyte (result
);
1097 /* CFNumber to a lisp integer or a lisp float. */
1100 cfnumber_to_lisp (number
)
1103 Lisp_Object result
= Qnil
;
1104 #if BITS_PER_EMACS_INT > 32
1106 CFNumberType emacs_int_type
= kCFNumberSInt64Type
;
1109 CFNumberType emacs_int_type
= kCFNumberSInt32Type
;
1113 if (CFNumberGetValue (number
, emacs_int_type
, &int_val
)
1114 && !FIXNUM_OVERFLOW_P (int_val
))
1115 result
= make_number (int_val
);
1117 if (CFNumberGetValue (number
, kCFNumberDoubleType
, &float_val
))
1118 result
= make_float (float_val
);
1123 /* CFDate to a list of three integers as in a return value of
1127 cfdate_to_lisp (date
)
1130 static const CFGregorianDate epoch_gdate
= {1970, 1, 1, 0, 0, 0.0};
1131 static CFAbsoluteTime epoch
= 0.0, sec
;
1135 epoch
= CFGregorianDateGetAbsoluteTime (epoch_gdate
, NULL
);
1137 sec
= CFDateGetAbsoluteTime (date
) - epoch
;
1138 high
= sec
/ 65536.0;
1139 low
= sec
- high
* 65536.0;
1141 return list3 (make_number (high
), make_number (low
), make_number (0));
1145 /* CFBoolean to a lisp symbol, `t' or `nil'. */
1148 cfboolean_to_lisp (boolean
)
1149 CFBooleanRef boolean
;
1151 return CFBooleanGetValue (boolean
) ? Qt
: Qnil
;
1155 /* Any Core Foundation object to a (lengthy) lisp string. */
1158 cfobject_desc_to_lisp (object
)
1161 Lisp_Object result
= Qnil
;
1162 CFStringRef desc
= CFCopyDescription (object
);
1166 result
= cfstring_to_lisp (desc
);
1174 /* Callback functions for cfproperty_list_to_lisp. */
1177 cfdictionary_add_to_list (key
, value
, context
)
1182 struct cfdict_context
*cxt
= (struct cfdict_context
*)context
;
1185 Fcons (Fcons (cfstring_to_lisp (key
),
1186 cfproperty_list_to_lisp (value
, cxt
->with_tag
,
1192 cfdictionary_puthash (key
, value
, context
)
1197 Lisp_Object lisp_key
= cfstring_to_lisp (key
);
1198 struct cfdict_context
*cxt
= (struct cfdict_context
*)context
;
1199 struct Lisp_Hash_Table
*h
= XHASH_TABLE (*(cxt
->result
));
1202 hash_lookup (h
, lisp_key
, &hash_code
);
1203 hash_put (h
, lisp_key
,
1204 cfproperty_list_to_lisp (value
, cxt
->with_tag
, cxt
->hash_bound
),
1209 /* Convert CFPropertyList PLIST to a lisp object. If WITH_TAG is
1210 non-zero, a symbol that represents the type of the original Core
1211 Foundation object is prepended. HASH_BOUND specifies which kinds
1212 of the lisp objects, alists or hash tables, are used as the targets
1213 of the conversion from CFDictionary. If HASH_BOUND is negative,
1214 always generate alists. If HASH_BOUND >= 0, generate an alist if
1215 the number of keys in the dictionary is smaller than HASH_BOUND,
1216 and a hash table otherwise. */
1219 cfproperty_list_to_lisp (plist
, with_tag
, hash_bound
)
1220 CFPropertyListRef plist
;
1221 int with_tag
, hash_bound
;
1223 CFTypeID type_id
= CFGetTypeID (plist
);
1224 Lisp_Object tag
= Qnil
, result
= Qnil
;
1225 struct gcpro gcpro1
, gcpro2
;
1227 GCPRO2 (tag
, result
);
1229 if (type_id
== CFStringGetTypeID ())
1232 result
= cfstring_to_lisp (plist
);
1234 else if (type_id
== CFNumberGetTypeID ())
1237 result
= cfnumber_to_lisp (plist
);
1239 else if (type_id
== CFBooleanGetTypeID ())
1242 result
= cfboolean_to_lisp (plist
);
1244 else if (type_id
== CFDateGetTypeID ())
1247 result
= cfdate_to_lisp (plist
);
1249 else if (type_id
== CFDataGetTypeID ())
1252 result
= cfdata_to_lisp (plist
);
1254 else if (type_id
== CFArrayGetTypeID ())
1256 CFIndex index
, count
= CFArrayGetCount (plist
);
1259 result
= Fmake_vector (make_number (count
), Qnil
);
1260 for (index
= 0; index
< count
; index
++)
1261 XVECTOR (result
)->contents
[index
] =
1262 cfproperty_list_to_lisp (CFArrayGetValueAtIndex (plist
, index
),
1263 with_tag
, hash_bound
);
1265 else if (type_id
== CFDictionaryGetTypeID ())
1267 struct cfdict_context context
;
1268 CFIndex count
= CFDictionaryGetCount (plist
);
1271 context
.result
= &result
;
1272 context
.with_tag
= with_tag
;
1273 context
.hash_bound
= hash_bound
;
1274 if (hash_bound
< 0 || count
< hash_bound
)
1277 CFDictionaryApplyFunction (plist
, cfdictionary_add_to_list
,
1282 result
= make_hash_table (Qequal
,
1283 make_number (count
),
1284 make_float (DEFAULT_REHASH_SIZE
),
1285 make_float (DEFAULT_REHASH_THRESHOLD
),
1287 CFDictionaryApplyFunction (plist
, cfdictionary_puthash
,
1297 result
= Fcons (tag
, result
);
1304 /***********************************************************************
1305 Emulation of the X Resource Manager
1306 ***********************************************************************/
1308 /* Parser functions for resource lines. Each function takes an
1309 address of a variable whose value points to the head of a string.
1310 The value will be advanced so that it points to the next character
1311 of the parsed part when the function returns.
1313 A resource name such as "Emacs*font" is parsed into a non-empty
1314 list called `quarks'. Each element is either a Lisp string that
1315 represents a concrete component, a Lisp symbol LOOSE_BINDING
1316 (actually Qlambda) that represents any number (>=0) of intervening
1317 components, or a Lisp symbol SINGLE_COMPONENT (actually Qquote)
1318 that represents as any single component. */
1322 #define LOOSE_BINDING Qlambda /* '*' ("L"oose) */
1323 #define SINGLE_COMPONENT Qquote /* '?' ("Q"uestion) */
1326 skip_white_space (p
)
1329 /* WhiteSpace = {<space> | <horizontal tab>} */
1330 while (*P
== ' ' || *P
== '\t')
1338 /* Comment = "!" {<any character except null or newline>} */
1351 /* Don't interpret filename. Just skip until the newline. */
1353 parse_include_file (p
)
1356 /* IncludeFile = "#" WhiteSpace "include" WhiteSpace FileName WhiteSpace */
1373 /* Binding = "." | "*" */
1374 if (*P
== '.' || *P
== '*')
1376 char binding
= *P
++;
1378 while (*P
== '.' || *P
== '*')
1391 /* Component = "?" | ComponentName
1392 ComponentName = NameChar {NameChar}
1393 NameChar = "a"-"z" | "A"-"Z" | "0"-"9" | "_" | "-" */
1397 return SINGLE_COMPONENT
;
1399 else if (isalnum (*P
) || *P
== '_' || *P
== '-')
1401 const char *start
= P
++;
1403 while (isalnum (*P
) || *P
== '_' || *P
== '-')
1406 return make_unibyte_string (start
, P
- start
);
1413 parse_resource_name (p
)
1416 Lisp_Object result
= Qnil
, component
;
1419 /* ResourceName = [Binding] {Component Binding} ComponentName */
1420 if (parse_binding (p
) == '*')
1421 result
= Fcons (LOOSE_BINDING
, result
);
1423 component
= parse_component (p
);
1424 if (NILP (component
))
1427 result
= Fcons (component
, result
);
1428 while ((binding
= parse_binding (p
)) != '\0')
1431 result
= Fcons (LOOSE_BINDING
, result
);
1432 component
= parse_component (p
);
1433 if (NILP (component
))
1436 result
= Fcons (component
, result
);
1439 /* The final component should not be '?'. */
1440 if (EQ (component
, SINGLE_COMPONENT
))
1443 return Fnreverse (result
);
1451 Lisp_Object seq
= Qnil
, result
;
1452 int buf_len
, total_len
= 0, len
, continue_p
;
1454 q
= strchr (P
, '\n');
1455 buf_len
= q
? q
- P
: strlen (P
);
1456 buf
= xmalloc (buf_len
);
1469 else if (*P
== '\\')
1474 else if (*P
== '\n')
1485 else if ('0' <= P
[0] && P
[0] <= '7'
1486 && '0' <= P
[1] && P
[1] <= '7'
1487 && '0' <= P
[2] && P
[2] <= '7')
1489 *q
++ = ((P
[0] - '0') << 6) + ((P
[1] - '0') << 3) + (P
[2] - '0');
1499 seq
= Fcons (make_unibyte_string (buf
, len
), seq
);
1504 q
= strchr (P
, '\n');
1505 len
= q
? q
- P
: strlen (P
);
1510 buf
= xmalloc (buf_len
);
1518 if (SBYTES (XCAR (seq
)) == total_len
)
1519 return make_string (SDATA (XCAR (seq
)), total_len
);
1522 buf
= xmalloc (total_len
);
1523 q
= buf
+ total_len
;
1524 for (; CONSP (seq
); seq
= XCDR (seq
))
1526 len
= SBYTES (XCAR (seq
));
1528 memcpy (q
, SDATA (XCAR (seq
)), len
);
1530 result
= make_string (buf
, total_len
);
1537 parse_resource_line (p
)
1540 Lisp_Object quarks
, value
;
1542 /* ResourceLine = Comment | IncludeFile | ResourceSpec | <empty line> */
1543 if (parse_comment (p
) || parse_include_file (p
))
1546 /* ResourceSpec = WhiteSpace ResourceName WhiteSpace ":" WhiteSpace Value */
1547 skip_white_space (p
);
1548 quarks
= parse_resource_name (p
);
1551 skip_white_space (p
);
1555 skip_white_space (p
);
1556 value
= parse_value (p
);
1557 return Fcons (quarks
, value
);
1560 /* Skip the remaining data as a dummy value. */
1567 /* Equivalents of X Resource Manager functions.
1569 An X Resource Database acts as a collection of resource names and
1570 associated values. It is implemented as a trie on quarks. Namely,
1571 each edge is labeled by either a string, LOOSE_BINDING, or
1572 SINGLE_COMPONENT. Each node has a node id, which is a unique
1573 nonnegative integer, and the root node id is 0. A database is
1574 implemented as a hash table that maps a pair (SRC-NODE-ID .
1575 EDGE-LABEL) to DEST-NODE-ID. It also holds a maximum node id used
1576 in the table as a value for HASHKEY_MAX_NID. A value associated to
1577 a node is recorded as a value for the node id.
1579 A database also has a cache for past queries as a value for
1580 HASHKEY_QUERY_CACHE. It is another hash table that maps
1581 "NAME-STRING\0CLASS-STRING" to the result of the query. */
1583 #define HASHKEY_MAX_NID (make_number (0))
1584 #define HASHKEY_QUERY_CACHE (make_number (-1))
1587 xrm_create_database ()
1589 XrmDatabase database
;
1591 database
= make_hash_table (Qequal
, make_number (DEFAULT_HASH_SIZE
),
1592 make_float (DEFAULT_REHASH_SIZE
),
1593 make_float (DEFAULT_REHASH_THRESHOLD
),
1595 Fputhash (HASHKEY_MAX_NID
, make_number (0), database
);
1596 Fputhash (HASHKEY_QUERY_CACHE
, Qnil
, database
);
1602 xrm_q_put_resource (database
, quarks
, value
)
1603 XrmDatabase database
;
1604 Lisp_Object quarks
, value
;
1606 struct Lisp_Hash_Table
*h
= XHASH_TABLE (database
);
1609 Lisp_Object node_id
, key
;
1611 max_nid
= XINT (Fgethash (HASHKEY_MAX_NID
, database
, Qnil
));
1613 XSETINT (node_id
, 0);
1614 for (; CONSP (quarks
); quarks
= XCDR (quarks
))
1616 key
= Fcons (node_id
, XCAR (quarks
));
1617 i
= hash_lookup (h
, key
, &hash_code
);
1621 XSETINT (node_id
, max_nid
);
1622 hash_put (h
, key
, node_id
, hash_code
);
1625 node_id
= HASH_VALUE (h
, i
);
1627 Fputhash (node_id
, value
, database
);
1629 Fputhash (HASHKEY_MAX_NID
, make_number (max_nid
), database
);
1630 Fputhash (HASHKEY_QUERY_CACHE
, Qnil
, database
);
1633 /* Merge multiple resource entries specified by DATA into a resource
1634 database DATABASE. DATA points to the head of a null-terminated
1635 string consisting of multiple resource lines. It's like a
1636 combination of XrmGetStringDatabase and XrmMergeDatabases. */
1639 xrm_merge_string_database (database
, data
)
1640 XrmDatabase database
;
1643 Lisp_Object quarks_value
;
1647 quarks_value
= parse_resource_line (&data
);
1648 if (!NILP (quarks_value
))
1649 xrm_q_put_resource (database
,
1650 XCAR (quarks_value
), XCDR (quarks_value
));
1655 xrm_q_get_resource_1 (database
, node_id
, quark_name
, quark_class
)
1656 XrmDatabase database
;
1657 Lisp_Object node_id
, quark_name
, quark_class
;
1659 struct Lisp_Hash_Table
*h
= XHASH_TABLE (database
);
1660 Lisp_Object key
, labels
[3], value
;
1663 if (!CONSP (quark_name
))
1664 return Fgethash (node_id
, database
, Qnil
);
1666 /* First, try tight bindings */
1667 labels
[0] = XCAR (quark_name
);
1668 labels
[1] = XCAR (quark_class
);
1669 labels
[2] = SINGLE_COMPONENT
;
1671 key
= Fcons (node_id
, Qnil
);
1672 for (k
= 0; k
< sizeof (labels
) / sizeof (*labels
); k
++)
1674 XSETCDR (key
, labels
[k
]);
1675 i
= hash_lookup (h
, key
, NULL
);
1678 value
= xrm_q_get_resource_1 (database
, HASH_VALUE (h
, i
),
1679 XCDR (quark_name
), XCDR (quark_class
));
1685 /* Then, try loose bindings */
1686 XSETCDR (key
, LOOSE_BINDING
);
1687 i
= hash_lookup (h
, key
, NULL
);
1690 value
= xrm_q_get_resource_1 (database
, HASH_VALUE (h
, i
),
1691 quark_name
, quark_class
);
1695 return xrm_q_get_resource_1 (database
, node_id
,
1696 XCDR (quark_name
), XCDR (quark_class
));
1703 xrm_q_get_resource (database
, quark_name
, quark_class
)
1704 XrmDatabase database
;
1705 Lisp_Object quark_name
, quark_class
;
1707 return xrm_q_get_resource_1 (database
, make_number (0),
1708 quark_name
, quark_class
);
1711 /* Retrieve a resource value for the specified NAME and CLASS from the
1712 resource database DATABASE. It corresponds to XrmGetResource. */
1715 xrm_get_resource (database
, name
, class)
1716 XrmDatabase database
;
1717 const char *name
, *class;
1719 Lisp_Object key
, query_cache
, quark_name
, quark_class
, tmp
;
1721 struct Lisp_Hash_Table
*h
;
1725 nc
= strlen (class);
1726 key
= make_uninit_string (nn
+ nc
+ 1);
1727 strcpy (SDATA (key
), name
);
1728 strncpy (SDATA (key
) + nn
+ 1, class, nc
);
1730 query_cache
= Fgethash (HASHKEY_QUERY_CACHE
, database
, Qnil
);
1731 if (NILP (query_cache
))
1733 query_cache
= make_hash_table (Qequal
, make_number (DEFAULT_HASH_SIZE
),
1734 make_float (DEFAULT_REHASH_SIZE
),
1735 make_float (DEFAULT_REHASH_THRESHOLD
),
1737 Fputhash (HASHKEY_QUERY_CACHE
, query_cache
, database
);
1739 h
= XHASH_TABLE (query_cache
);
1740 i
= hash_lookup (h
, key
, &hash_code
);
1742 return HASH_VALUE (h
, i
);
1744 quark_name
= parse_resource_name (&name
);
1747 for (tmp
= quark_name
, nn
= 0; CONSP (tmp
); tmp
= XCDR (tmp
), nn
++)
1748 if (!STRINGP (XCAR (tmp
)))
1751 quark_class
= parse_resource_name (&class);
1754 for (tmp
= quark_class
, nc
= 0; CONSP (tmp
); tmp
= XCDR (tmp
), nc
++)
1755 if (!STRINGP (XCAR (tmp
)))
1762 tmp
= xrm_q_get_resource (database
, quark_name
, quark_class
);
1763 hash_put (h
, key
, tmp
, hash_code
);
1768 #if TARGET_API_MAC_CARBON
1770 xrm_cfproperty_list_to_value (plist
)
1771 CFPropertyListRef plist
;
1773 CFTypeID type_id
= CFGetTypeID (plist
);
1775 if (type_id
== CFStringGetTypeID ())
1776 return cfstring_to_lisp (plist
);
1777 else if (type_id
== CFNumberGetTypeID ())
1780 Lisp_Object result
= Qnil
;
1782 string
= CFStringCreateWithFormat (NULL
, NULL
, CFSTR ("%@"), plist
);
1785 result
= cfstring_to_lisp (string
);
1790 else if (type_id
== CFBooleanGetTypeID ())
1791 return build_string (CFBooleanGetValue (plist
) ? "true" : "false");
1792 else if (type_id
== CFDataGetTypeID ())
1793 return cfdata_to_lisp (plist
);
1799 /* Create a new resource database from the preferences for the
1800 application APPLICATION. APPLICATION is either a string that
1801 specifies an application ID, or NULL that represents the current
1805 xrm_get_preference_database (application
)
1806 const char *application
;
1808 #if TARGET_API_MAC_CARBON
1809 CFStringRef app_id
, *keys
, user_doms
[2], host_doms
[2];
1810 CFMutableSetRef key_set
= NULL
;
1811 CFArrayRef key_array
;
1812 CFIndex index
, count
;
1814 XrmDatabase database
;
1815 Lisp_Object quarks
= Qnil
, value
= Qnil
;
1816 CFPropertyListRef plist
;
1818 struct gcpro gcpro1
, gcpro2
, gcpro3
;
1820 user_doms
[0] = kCFPreferencesCurrentUser
;
1821 user_doms
[1] = kCFPreferencesAnyUser
;
1822 host_doms
[0] = kCFPreferencesCurrentHost
;
1823 host_doms
[1] = kCFPreferencesAnyHost
;
1825 database
= xrm_create_database ();
1827 GCPRO3 (database
, quarks
, value
);
1829 app_id
= kCFPreferencesCurrentApplication
;
1832 app_id
= cfstring_create_with_utf8_cstring (application
);
1836 if (!CFPreferencesAppSynchronize (app_id
))
1839 key_set
= CFSetCreateMutable (NULL
, 0, &kCFCopyStringSetCallBacks
);
1840 if (key_set
== NULL
)
1842 for (iu
= 0; iu
< sizeof (user_doms
) / sizeof (*user_doms
) ; iu
++)
1843 for (ih
= 0; ih
< sizeof (host_doms
) / sizeof (*host_doms
); ih
++)
1845 key_array
= CFPreferencesCopyKeyList (app_id
, user_doms
[iu
],
1849 count
= CFArrayGetCount (key_array
);
1850 for (index
= 0; index
< count
; index
++)
1851 CFSetAddValue (key_set
,
1852 CFArrayGetValueAtIndex (key_array
, index
));
1853 CFRelease (key_array
);
1857 count
= CFSetGetCount (key_set
);
1858 keys
= xmalloc (sizeof (CFStringRef
) * count
);
1859 CFSetGetValues (key_set
, (const void **)keys
);
1860 for (index
= 0; index
< count
; index
++)
1862 res_name
= SDATA (cfstring_to_lisp_nodecode (keys
[index
]));
1863 quarks
= parse_resource_name (&res_name
);
1864 if (!(NILP (quarks
) || *res_name
))
1866 plist
= CFPreferencesCopyAppValue (keys
[index
], app_id
);
1867 value
= xrm_cfproperty_list_to_value (plist
);
1870 xrm_q_put_resource (database
, quarks
, value
);
1877 CFRelease (key_set
);
1884 return xrm_create_database ();
1891 /* The following functions with "sys_" prefix are stubs to Unix
1892 functions that have already been implemented by CW or MPW. The
1893 calls to them in Emacs source course are #define'd to call the sys_
1894 versions by the header files s-mac.h. In these stubs pathnames are
1895 converted between their Unix and Mac forms. */
1898 /* Unix epoch is Jan 1, 1970 while Mac epoch is Jan 1, 1904: 66 years
1899 + 17 leap days. These are for adjusting time values returned by
1900 MacOS Toolbox functions. */
1902 #define MAC_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
1905 #if __MSL__ < 0x6000
1906 /* CW Pro 5 epoch is Jan 1, 1900 (aaarghhhhh!); remember, 1900 is not
1907 a leap year! This is for adjusting time_t values returned by MSL
1909 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 70 + 17) * 24 * 60 * 60)
1910 #else /* __MSL__ >= 0x6000 */
1911 /* CW changes Pro 6 to follow Unix! */
1912 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
1913 #endif /* __MSL__ >= 0x6000 */
1915 /* MPW library functions follow Unix (confused?). */
1916 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
1917 #else /* not __MRC__ */
1919 #endif /* not __MRC__ */
1922 /* Define our own stat function for both MrC and CW. The reason for
1923 doing this: "stat" is both the name of a struct and function name:
1924 can't use the same trick like that for sys_open, sys_close, etc. to
1925 redirect Emacs's calls to our own version that converts Unix style
1926 filenames to Mac style filename because all sorts of compilation
1927 errors will be generated if stat is #define'd to be sys_stat. */
1930 stat_noalias (const char *path
, struct stat
*buf
)
1932 char mac_pathname
[MAXPATHLEN
+1];
1935 if (posix_to_mac_pathname (path
, mac_pathname
, MAXPATHLEN
+1) == 0)
1938 c2pstr (mac_pathname
);
1939 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
1940 cipb
.hFileInfo
.ioVRefNum
= 0;
1941 cipb
.hFileInfo
.ioDirID
= 0;
1942 cipb
.hFileInfo
.ioFDirIndex
= 0;
1943 /* set to 0 to get information about specific dir or file */
1945 errno
= PBGetCatInfo (&cipb
, false);
1946 if (errno
== -43) /* -43: fnfErr defined in Errors.h */
1951 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* bit 4 = 1 for directories */
1953 buf
->st_mode
= S_IFDIR
| S_IREAD
| S_IEXEC
;
1955 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x1))
1956 buf
->st_mode
|= S_IWRITE
; /* bit 1 = 1 for locked files/directories */
1957 buf
->st_ino
= cipb
.dirInfo
.ioDrDirID
;
1958 buf
->st_dev
= cipb
.dirInfo
.ioVRefNum
;
1959 buf
->st_size
= cipb
.dirInfo
.ioDrNmFls
;
1960 /* size of dir = number of files and dirs */
1963 = cipb
.dirInfo
.ioDrMdDat
- MAC_UNIX_EPOCH_DIFF
;
1964 buf
->st_ctime
= cipb
.dirInfo
.ioDrCrDat
- MAC_UNIX_EPOCH_DIFF
;
1968 buf
->st_mode
= S_IFREG
| S_IREAD
;
1969 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x1))
1970 buf
->st_mode
|= S_IWRITE
; /* bit 1 = 1 for locked files/directories */
1971 if (cipb
.hFileInfo
.ioFlFndrInfo
.fdType
== 'APPL')
1972 buf
->st_mode
|= S_IEXEC
;
1973 buf
->st_ino
= cipb
.hFileInfo
.ioDirID
;
1974 buf
->st_dev
= cipb
.hFileInfo
.ioVRefNum
;
1975 buf
->st_size
= cipb
.hFileInfo
.ioFlLgLen
;
1978 = cipb
.hFileInfo
.ioFlMdDat
- MAC_UNIX_EPOCH_DIFF
;
1979 buf
->st_ctime
= cipb
.hFileInfo
.ioFlCrDat
- MAC_UNIX_EPOCH_DIFF
;
1982 if (cipb
.hFileInfo
.ioFlFndrInfo
.fdFlags
& 0x8000)
1984 /* identify alias files as symlinks */
1985 buf
->st_mode
&= ~S_IFREG
;
1986 buf
->st_mode
|= S_IFLNK
;
1990 buf
->st_uid
= getuid ();
1991 buf
->st_gid
= getgid ();
1999 lstat (const char *path
, struct stat
*buf
)
2002 char true_pathname
[MAXPATHLEN
+1];
2004 /* Try looking for the file without resolving aliases first. */
2005 if ((result
= stat_noalias (path
, buf
)) >= 0)
2008 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
2011 return stat_noalias (true_pathname
, buf
);
2016 stat (const char *path
, struct stat
*sb
)
2019 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
2022 if ((result
= stat_noalias (path
, sb
)) >= 0 &&
2023 ! (sb
->st_mode
& S_IFLNK
))
2026 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
2029 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
2032 fully_resolved_name
[len
] = '\0';
2033 /* in fact our readlink terminates strings */
2034 return lstat (fully_resolved_name
, sb
);
2037 return lstat (true_pathname
, sb
);
2042 /* CW defines fstat in stat.mac.c while MPW does not provide this
2043 function. Without the information of how to get from a file
2044 descriptor in MPW StdCLib to a Mac OS file spec, it should be hard
2045 to implement this function. Fortunately, there is only one place
2046 where this function is called in our configuration: in fileio.c,
2047 where only the st_dev and st_ino fields are used to determine
2048 whether two fildes point to different i-nodes to prevent copying
2049 a file onto itself equal. What we have here probably needs
2053 fstat (int fildes
, struct stat
*buf
)
2056 buf
->st_ino
= fildes
;
2057 buf
->st_mode
= S_IFREG
; /* added by T.I. for the copy-file */
2058 return 0; /* success */
2060 #endif /* __MRC__ */
2064 mkdir (const char *dirname
, int mode
)
2066 #pragma unused(mode)
2069 char true_pathname
[MAXPATHLEN
+1], mac_pathname
[MAXPATHLEN
+1];
2071 if (find_true_pathname (dirname
, true_pathname
, MAXPATHLEN
+1) == -1)
2074 if (posix_to_mac_pathname (true_pathname
, mac_pathname
, MAXPATHLEN
+1) == 0)
2077 c2pstr (mac_pathname
);
2078 hfpb
.ioNamePtr
= mac_pathname
;
2079 hfpb
.ioVRefNum
= 0; /* ignored unless name is invalid */
2080 hfpb
.ioDirID
= 0; /* parent is the root */
2082 errno
= PBDirCreate ((HParmBlkPtr
) &hfpb
, false);
2083 /* just return the Mac OSErr code for now */
2084 return errno
== noErr
? 0 : -1;
2089 sys_rmdir (const char *dirname
)
2092 char mac_pathname
[MAXPATHLEN
+1];
2094 if (posix_to_mac_pathname (dirname
, mac_pathname
, MAXPATHLEN
+1) == 0)
2097 c2pstr (mac_pathname
);
2098 hfpb
.ioNamePtr
= mac_pathname
;
2099 hfpb
.ioVRefNum
= 0; /* ignored unless name is invalid */
2100 hfpb
.ioDirID
= 0; /* parent is the root */
2102 errno
= PBHDelete ((HParmBlkPtr
) &hfpb
, false);
2103 return errno
== noErr
? 0 : -1;
2108 /* No implementation yet. */
2110 execvp (const char *path
, ...)
2114 #endif /* __MRC__ */
2118 utime (const char *path
, const struct utimbuf
*times
)
2120 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
2122 char mac_pathname
[MAXPATHLEN
+1];
2125 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
2128 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
2130 fully_resolved_name
[len
] = '\0';
2132 strcpy (fully_resolved_name
, true_pathname
);
2134 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
2137 c2pstr (mac_pathname
);
2138 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
2139 cipb
.hFileInfo
.ioVRefNum
= 0;
2140 cipb
.hFileInfo
.ioDirID
= 0;
2141 cipb
.hFileInfo
.ioFDirIndex
= 0;
2142 /* set to 0 to get information about specific dir or file */
2144 errno
= PBGetCatInfo (&cipb
, false);
2148 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* bit 4 = 1 for directories */
2151 cipb
.dirInfo
.ioDrMdDat
= times
->modtime
+ MAC_UNIX_EPOCH_DIFF
;
2153 GetDateTime (&cipb
.dirInfo
.ioDrMdDat
);
2158 cipb
.hFileInfo
.ioFlMdDat
= times
->modtime
+ MAC_UNIX_EPOCH_DIFF
;
2160 GetDateTime (&cipb
.hFileInfo
.ioFlMdDat
);
2163 errno
= PBSetCatInfo (&cipb
, false);
2164 return errno
== noErr
? 0 : -1;
2178 /* Like stat, but test for access mode in hfpb.ioFlAttrib */
2180 access (const char *path
, int mode
)
2182 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
2184 char mac_pathname
[MAXPATHLEN
+1];
2187 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
2190 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
2192 fully_resolved_name
[len
] = '\0';
2194 strcpy (fully_resolved_name
, true_pathname
);
2196 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
2199 c2pstr (mac_pathname
);
2200 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
2201 cipb
.hFileInfo
.ioVRefNum
= 0;
2202 cipb
.hFileInfo
.ioDirID
= 0;
2203 cipb
.hFileInfo
.ioFDirIndex
= 0;
2204 /* set to 0 to get information about specific dir or file */
2206 errno
= PBGetCatInfo (&cipb
, false);
2210 if (mode
== F_OK
) /* got this far, file exists */
2214 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* path refers to a directory */
2218 if (cipb
.hFileInfo
.ioFlFndrInfo
.fdType
== 'APPL')
2225 return (cipb
.hFileInfo
.ioFlAttrib
& 0x1) ? -1 : 0;
2226 /* don't allow if lock bit is on */
2232 #define DEV_NULL_FD 0x10000
2236 sys_open (const char *path
, int oflag
)
2238 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
2240 char mac_pathname
[MAXPATHLEN
+1];
2242 if (strcmp (path
, "/dev/null") == 0)
2243 return DEV_NULL_FD
; /* some bogus fd to be ignored in write */
2245 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
2248 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
2250 fully_resolved_name
[len
] = '\0';
2252 strcpy (fully_resolved_name
, true_pathname
);
2254 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
2259 int res
= open (mac_pathname
, oflag
);
2260 /* if (oflag == O_WRONLY || oflag == O_RDWR) */
2261 if (oflag
& O_CREAT
)
2262 fsetfileinfo (mac_pathname
, MAC_EMACS_CREATOR_CODE
, 'TEXT');
2264 #else /* not __MRC__ */
2265 return open (mac_pathname
, oflag
);
2266 #endif /* not __MRC__ */
2273 sys_creat (const char *path
, mode_t mode
)
2275 char true_pathname
[MAXPATHLEN
+1];
2277 char mac_pathname
[MAXPATHLEN
+1];
2279 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
2282 if (!posix_to_mac_pathname (true_pathname
, mac_pathname
, MAXPATHLEN
+1))
2287 int result
= creat (mac_pathname
);
2288 fsetfileinfo (mac_pathname
, MAC_EMACS_CREATOR_CODE
, 'TEXT');
2290 #else /* not __MRC__ */
2291 return creat (mac_pathname
, mode
);
2292 #endif /* not __MRC__ */
2299 sys_unlink (const char *path
)
2301 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
2303 char mac_pathname
[MAXPATHLEN
+1];
2305 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
2308 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
2310 fully_resolved_name
[len
] = '\0';
2312 strcpy (fully_resolved_name
, true_pathname
);
2314 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
2317 return unlink (mac_pathname
);
2323 sys_read (int fildes
, char *buf
, int count
)
2325 if (fildes
== 0) /* this should not be used for console input */
2328 #if __MSL__ >= 0x6000
2329 return _read (fildes
, buf
, count
);
2331 return read (fildes
, buf
, count
);
2338 sys_write (int fildes
, const char *buf
, int count
)
2340 if (fildes
== DEV_NULL_FD
)
2343 #if __MSL__ >= 0x6000
2344 return _write (fildes
, buf
, count
);
2346 return write (fildes
, buf
, count
);
2353 sys_rename (const char * old_name
, const char * new_name
)
2355 char true_old_pathname
[MAXPATHLEN
+1], true_new_pathname
[MAXPATHLEN
+1];
2356 char fully_resolved_old_name
[MAXPATHLEN
+1];
2358 char mac_old_name
[MAXPATHLEN
+1], mac_new_name
[MAXPATHLEN
+1];
2360 if (find_true_pathname (old_name
, true_old_pathname
, MAXPATHLEN
+1) == -1)
2363 len
= readlink (true_old_pathname
, fully_resolved_old_name
, MAXPATHLEN
);
2365 fully_resolved_old_name
[len
] = '\0';
2367 strcpy (fully_resolved_old_name
, true_old_pathname
);
2369 if (find_true_pathname (new_name
, true_new_pathname
, MAXPATHLEN
+1) == -1)
2372 if (strcmp (fully_resolved_old_name
, true_new_pathname
) == 0)
2375 if (!posix_to_mac_pathname (fully_resolved_old_name
,
2380 if (!posix_to_mac_pathname(true_new_pathname
, mac_new_name
, MAXPATHLEN
+1))
2383 /* If a file with new_name already exists, rename deletes the old
2384 file in Unix. CW version fails in these situation. So we add a
2385 call to unlink here. */
2386 (void) unlink (mac_new_name
);
2388 return rename (mac_old_name
, mac_new_name
);
2393 extern FILE *fopen (const char *name
, const char *mode
);
2395 sys_fopen (const char *name
, const char *mode
)
2397 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
2399 char mac_pathname
[MAXPATHLEN
+1];
2401 if (find_true_pathname (name
, true_pathname
, MAXPATHLEN
+1) == -1)
2404 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
2406 fully_resolved_name
[len
] = '\0';
2408 strcpy (fully_resolved_name
, true_pathname
);
2410 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
2415 if (mode
[0] == 'w' || mode
[0] == 'a')
2416 fsetfileinfo (mac_pathname
, MAC_EMACS_CREATOR_CODE
, 'TEXT');
2417 #endif /* not __MRC__ */
2418 return fopen (mac_pathname
, mode
);
2423 extern Boolean mac_wait_next_event
P_ ((EventRecord
*, UInt32
, Boolean
));
2426 select (nfds
, rfds
, wfds
, efds
, timeout
)
2428 SELECT_TYPE
*rfds
, *wfds
, *efds
;
2429 EMACS_TIME
*timeout
;
2431 OSStatus err
= noErr
;
2433 /* Can only handle wait for keyboard input. */
2434 if (nfds
> 1 || wfds
|| efds
)
2437 /* Try detect_input_pending before ReceiveNextEvent in the same
2438 BLOCK_INPUT block, in case that some input has already been read
2441 ENABLE_WAKEUP_FROM_RNE
;
2442 if (!detect_input_pending ())
2444 #if TARGET_API_MAC_CARBON
2445 EventTimeout timeoutval
=
2447 ? (EMACS_SECS (*timeout
) * kEventDurationSecond
2448 + EMACS_USECS (*timeout
) * kEventDurationMicrosecond
)
2449 : kEventDurationForever
);
2451 if (timeoutval
== 0.0)
2452 err
= eventLoopTimedOutErr
;
2454 err
= ReceiveNextEvent (0, NULL
, timeoutval
,
2455 kEventLeaveInQueue
, NULL
);
2456 #else /* not TARGET_API_MAC_CARBON */
2458 UInt32 sleep_time
= EMACS_SECS (*timeout
) * 60 +
2459 ((EMACS_USECS (*timeout
) * 60) / 1000000);
2461 if (sleep_time
== 0)
2462 err
= -9875; /* eventLoopTimedOutErr */
2465 if (mac_wait_next_event (&e
, sleep_time
, false))
2468 err
= -9875; /* eventLoopTimedOutErr */
2470 #endif /* not TARGET_API_MAC_CARBON */
2472 DISABLE_WAKEUP_FROM_RNE
;
2477 /* Pretend that `select' is interrupted by a signal. */
2478 detect_input_pending ();
2491 /* Simulation of SIGALRM. The stub for function signal stores the
2492 signal handler function in alarm_signal_func if a SIGALRM is
2496 #include "syssignal.h"
2498 static TMTask mac_atimer_task
;
2500 static QElemPtr mac_atimer_qlink
= (QElemPtr
) &mac_atimer_task
;
2502 static int signal_mask
= 0;
2505 __sigfun alarm_signal_func
= (__sigfun
) 0;
2507 __signal_func_ptr alarm_signal_func
= (__signal_func_ptr
) 0;
2508 #else /* not __MRC__ and not __MWERKS__ */
2510 #endif /* not __MRC__ and not __MWERKS__ */
2514 extern __sigfun
signal (int signal
, __sigfun signal_func
);
2516 sys_signal (int signal_num
, __sigfun signal_func
)
2518 extern __signal_func_ptr
signal (int signal
, __signal_func_ptr signal_func
);
2520 sys_signal (int signal_num
, __signal_func_ptr signal_func
)
2521 #else /* not __MRC__ and not __MWERKS__ */
2523 #endif /* not __MRC__ and not __MWERKS__ */
2525 if (signal_num
!= SIGALRM
)
2526 return signal (signal_num
, signal_func
);
2530 __sigfun old_signal_func
;
2532 __signal_func_ptr old_signal_func
;
2536 old_signal_func
= alarm_signal_func
;
2537 alarm_signal_func
= signal_func
;
2538 return old_signal_func
;
2544 mac_atimer_handler (qlink
)
2547 if (alarm_signal_func
)
2548 (alarm_signal_func
) (SIGALRM
);
2553 set_mac_atimer (count
)
2556 static TimerUPP mac_atimer_handlerUPP
= NULL
;
2558 if (mac_atimer_handlerUPP
== NULL
)
2559 mac_atimer_handlerUPP
= NewTimerUPP (mac_atimer_handler
);
2560 mac_atimer_task
.tmCount
= 0;
2561 mac_atimer_task
.tmAddr
= mac_atimer_handlerUPP
;
2562 mac_atimer_qlink
= (QElemPtr
) &mac_atimer_task
;
2563 InsTime (mac_atimer_qlink
);
2565 PrimeTime (mac_atimer_qlink
, count
);
2570 remove_mac_atimer (remaining_count
)
2571 long *remaining_count
;
2573 if (mac_atimer_qlink
)
2575 RmvTime (mac_atimer_qlink
);
2576 if (remaining_count
)
2577 *remaining_count
= mac_atimer_task
.tmCount
;
2578 mac_atimer_qlink
= NULL
;
2590 int old_mask
= signal_mask
;
2592 signal_mask
|= mask
;
2594 if ((old_mask
^ signal_mask
) & sigmask (SIGALRM
))
2595 remove_mac_atimer (NULL
);
2602 sigsetmask (int mask
)
2604 int old_mask
= signal_mask
;
2608 if ((old_mask
^ signal_mask
) & sigmask (SIGALRM
))
2609 if (signal_mask
& sigmask (SIGALRM
))
2610 remove_mac_atimer (NULL
);
2612 set_mac_atimer (mac_atimer_task
.tmCount
);
2621 long remaining_count
;
2623 if (remove_mac_atimer (&remaining_count
) == 0)
2625 set_mac_atimer (seconds
* 1000);
2627 return remaining_count
/ 1000;
2631 mac_atimer_task
.tmCount
= seconds
* 1000;
2639 setitimer (which
, value
, ovalue
)
2641 const struct itimerval
*value
;
2642 struct itimerval
*ovalue
;
2644 long remaining_count
;
2645 long count
= (EMACS_SECS (value
->it_value
) * 1000
2646 + (EMACS_USECS (value
->it_value
) + 999) / 1000);
2648 if (remove_mac_atimer (&remaining_count
) == 0)
2652 bzero (ovalue
, sizeof (*ovalue
));
2653 EMACS_SET_SECS_USECS (ovalue
->it_value
, remaining_count
/ 1000,
2654 (remaining_count
% 1000) * 1000);
2656 set_mac_atimer (count
);
2659 mac_atimer_task
.tmCount
= count
;
2665 /* gettimeofday should return the amount of time (in a timeval
2666 structure) since midnight today. The toolbox function Microseconds
2667 returns the number of microseconds (in a UnsignedWide value) since
2668 the machine was booted. Also making this complicated is WideAdd,
2669 WideSubtract, etc. take wide values. */
2676 static wide wall_clock_at_epoch
, clicks_at_epoch
;
2677 UnsignedWide uw_microseconds
;
2678 wide w_microseconds
;
2679 time_t sys_time (time_t *);
2681 /* If this function is called for the first time, record the number
2682 of seconds since midnight and the number of microseconds since
2683 boot at the time of this first call. */
2688 systime
= sys_time (NULL
);
2689 /* Store microseconds since midnight in wall_clock_at_epoch. */
2690 WideMultiply (systime
, 1000000L, &wall_clock_at_epoch
);
2691 Microseconds (&uw_microseconds
);
2692 /* Store microseconds since boot in clicks_at_epoch. */
2693 clicks_at_epoch
.hi
= uw_microseconds
.hi
;
2694 clicks_at_epoch
.lo
= uw_microseconds
.lo
;
2697 /* Get time since boot */
2698 Microseconds (&uw_microseconds
);
2700 /* Convert to time since midnight*/
2701 w_microseconds
.hi
= uw_microseconds
.hi
;
2702 w_microseconds
.lo
= uw_microseconds
.lo
;
2703 WideSubtract (&w_microseconds
, &clicks_at_epoch
);
2704 WideAdd (&w_microseconds
, &wall_clock_at_epoch
);
2705 tp
->tv_sec
= WideDivide (&w_microseconds
, 1000000L, &tp
->tv_usec
);
2713 sleep (unsigned int seconds
)
2715 unsigned long time_up
;
2718 time_up
= TickCount () + seconds
* 60;
2719 while (TickCount () < time_up
)
2721 /* Accept no event; just wait. by T.I. */
2722 WaitNextEvent (0, &e
, 30, NULL
);
2727 #endif /* __MRC__ */
2730 /* The time functions adjust time values according to the difference
2731 between the Unix and CW epoches. */
2734 extern struct tm
*gmtime (const time_t *);
2736 sys_gmtime (const time_t *timer
)
2738 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
2740 return gmtime (&unix_time
);
2745 extern struct tm
*localtime (const time_t *);
2747 sys_localtime (const time_t *timer
)
2749 #if __MSL__ >= 0x6000
2750 time_t unix_time
= *timer
;
2752 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
2755 return localtime (&unix_time
);
2760 extern char *ctime (const time_t *);
2762 sys_ctime (const time_t *timer
)
2764 #if __MSL__ >= 0x6000
2765 time_t unix_time
= *timer
;
2767 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
2770 return ctime (&unix_time
);
2775 extern time_t time (time_t *);
2777 sys_time (time_t *timer
)
2779 #if __MSL__ >= 0x6000
2780 time_t mac_time
= time (NULL
);
2782 time_t mac_time
= time (NULL
) - CW_OR_MPW_UNIX_EPOCH_DIFF
;
2792 /* no subprocesses, empty wait */
2802 croak (char *badfunc
)
2804 printf ("%s not yet implemented\r\n", badfunc
);
2810 mktemp (char *template)
2815 len
= strlen (template);
2817 while (k
>= 0 && template[k
] == 'X')
2820 k
++; /* make k index of first 'X' */
2824 /* Zero filled, number of digits equal to the number of X's. */
2825 sprintf (&template[k
], "%0*d", len
-k
, seqnum
++);
2834 /* Emulate getpwuid, getpwnam and others. */
2836 #define PASSWD_FIELD_SIZE 256
2838 static char my_passwd_name
[PASSWD_FIELD_SIZE
];
2839 static char my_passwd_dir
[MAXPATHLEN
+1];
2841 static struct passwd my_passwd
=
2847 static struct group my_group
=
2849 /* There are no groups on the mac, so we just return "root" as the
2855 /* Initialized by main () in macterm.c to pathname of emacs directory. */
2857 char emacs_passwd_dir
[MAXPATHLEN
+1];
2863 init_emacs_passwd_dir ()
2867 if (getwd (emacs_passwd_dir
) && getwd (my_passwd_dir
))
2869 /* Need pathname of first ancestor that begins with "emacs"
2870 since Mac emacs application is somewhere in the emacs-*
2872 int len
= strlen (emacs_passwd_dir
);
2874 /* j points to the "/" following the directory name being
2877 while (i
>= 0 && !found
)
2879 while (i
>= 0 && emacs_passwd_dir
[i
] != '/')
2881 if (emacs_passwd_dir
[i
] == '/' && i
+5 < len
)
2882 found
= (strncmp (&(emacs_passwd_dir
[i
+1]), "emacs", 5) == 0);
2884 emacs_passwd_dir
[j
+1] = '\0';
2895 /* Setting to "/" probably won't work but set it to something
2897 strcpy (emacs_passwd_dir
, "/");
2898 strcpy (my_passwd_dir
, "/");
2903 static struct passwd emacs_passwd
=
2909 static int my_passwd_inited
= 0;
2917 /* Note: my_passwd_dir initialized in int_emacs_passwd_dir to
2918 directory where Emacs was started. */
2920 owner_name
= (char **) GetResource ('STR ',-16096);
2924 BlockMove ((unsigned char *) *owner_name
,
2925 (unsigned char *) my_passwd_name
,
2927 HUnlock (owner_name
);
2928 p2cstr ((unsigned char *) my_passwd_name
);
2931 my_passwd_name
[0] = 0;
2936 getpwuid (uid_t uid
)
2938 if (!my_passwd_inited
)
2941 my_passwd_inited
= 1;
2949 getgrgid (gid_t gid
)
2956 getpwnam (const char *name
)
2958 if (strcmp (name
, "emacs") == 0)
2959 return &emacs_passwd
;
2961 if (!my_passwd_inited
)
2964 my_passwd_inited
= 1;
2971 /* The functions fork, kill, sigsetmask, sigblock, request_sigio,
2972 setpgrp, setpriority, and unrequest_sigio are defined to be empty
2993 error ("Can't spawn subshell");
2998 request_sigio (void)
3004 unrequest_sigio (void)
3019 pipe (int _fildes
[2])
3026 /* Hard and symbolic links. */
3029 symlink (const char *name1
, const char *name2
)
3037 link (const char *name1
, const char *name2
)
3043 #endif /* ! MAC_OSX */
3045 /* Determine the path name of the file specified by VREFNUM, DIRID,
3046 and NAME and place that in the buffer PATH of length
3049 path_from_vol_dir_name (char *path
, int man_path_len
, short vol_ref_num
,
3050 long dir_id
, ConstStr255Param name
)
3056 if (strlen (name
) > man_path_len
)
3059 memcpy (dir_name
, name
, name
[0]+1);
3060 memcpy (path
, name
, name
[0]+1);
3063 cipb
.dirInfo
.ioDrParID
= dir_id
;
3064 cipb
.dirInfo
.ioNamePtr
= dir_name
;
3068 cipb
.dirInfo
.ioVRefNum
= vol_ref_num
;
3069 cipb
.dirInfo
.ioFDirIndex
= -1;
3070 cipb
.dirInfo
.ioDrDirID
= cipb
.dirInfo
.ioDrParID
;
3071 /* go up to parent each time */
3073 err
= PBGetCatInfo (&cipb
, false);
3078 if (strlen (dir_name
) + strlen (path
) + 1 >= man_path_len
)
3081 strcat (dir_name
, ":");
3082 strcat (dir_name
, path
);
3083 /* attach to front since we're going up directory tree */
3084 strcpy (path
, dir_name
);
3086 while (cipb
.dirInfo
.ioDrDirID
!= fsRtDirID
);
3087 /* stop when we see the volume's root directory */
3089 return 1; /* success */
3096 posix_pathname_to_fsspec (ufn
, fs
)
3100 Str255 mac_pathname
;
3102 if (posix_to_mac_pathname (ufn
, mac_pathname
, sizeof (mac_pathname
)) == 0)
3106 c2pstr (mac_pathname
);
3107 return FSMakeFSSpec (0, 0, mac_pathname
, fs
);
3112 fsspec_to_posix_pathname (fs
, ufn
, ufnbuflen
)
3117 char mac_pathname
[MAXPATHLEN
];
3119 if (path_from_vol_dir_name (mac_pathname
, sizeof (mac_pathname
) - 1,
3120 fs
->vRefNum
, fs
->parID
, fs
->name
)
3121 && mac_to_posix_pathname (mac_pathname
, ufn
, ufnbuflen
))
3128 readlink (const char *path
, char *buf
, int bufsiz
)
3130 char mac_sym_link_name
[MAXPATHLEN
+1];
3133 Boolean target_is_folder
, was_aliased
;
3134 Str255 directory_name
, mac_pathname
;
3137 if (posix_to_mac_pathname (path
, mac_sym_link_name
, MAXPATHLEN
+1) == 0)
3140 c2pstr (mac_sym_link_name
);
3141 err
= FSMakeFSSpec (0, 0, mac_sym_link_name
, &fsspec
);
3148 err
= ResolveAliasFile (&fsspec
, true, &target_is_folder
, &was_aliased
);
3149 if (err
!= noErr
|| !was_aliased
)
3155 if (path_from_vol_dir_name (mac_pathname
, 255, fsspec
.vRefNum
, fsspec
.parID
,
3162 if (mac_to_posix_pathname (mac_pathname
, buf
, bufsiz
) == 0)
3168 return strlen (buf
);
3172 /* Convert a path to one with aliases fully expanded. */
3175 find_true_pathname (const char *path
, char *buf
, int bufsiz
)
3177 char *q
, temp
[MAXPATHLEN
+1];
3181 if (bufsiz
<= 0 || path
== 0 || path
[0] == '\0')
3188 q
= strchr (p
+ 1, '/');
3190 q
= strchr (p
, '/');
3191 len
= 0; /* loop may not be entered, e.g., for "/" */
3196 strncat (temp
, p
, q
- p
);
3197 len
= readlink (temp
, buf
, bufsiz
);
3200 if (strlen (temp
) + 1 > bufsiz
)
3210 if (len
+ strlen (p
) + 1 >= bufsiz
)
3214 return len
+ strlen (p
);
3219 umask (mode_t numask
)
3221 static mode_t mask
= 022;
3222 mode_t oldmask
= mask
;
3229 chmod (const char *path
, mode_t mode
)
3231 /* say it always succeed for now */
3237 fchmod (int fd
, mode_t mode
)
3239 /* say it always succeed for now */
3245 fchown (int fd
, uid_t owner
, gid_t group
)
3247 /* say it always succeed for now */
3256 return fcntl (oldd
, F_DUPFD
, 0);
3258 /* current implementation of fcntl in fcntl.mac.c simply returns old
3260 return fcntl (oldd
, F_DUPFD
);
3267 /* This is from the original sysdep.c. Emulate BSD dup2. First close
3268 newd if it already exists. Then, attempt to dup oldd. If not
3269 successful, call dup2 recursively until we are, then close the
3270 unsuccessful ones. */
3273 dup2 (int oldd
, int newd
)
3284 ret
= dup2 (oldd
, newd
);
3290 /* let it fail for now */
3307 ioctl (int d
, int request
, void *argp
)
3317 if (fildes
>=0 && fildes
<= 2)
3350 #endif /* __MRC__ */
3354 #if __MSL__ < 0x6000
3362 #endif /* __MWERKS__ */
3364 #endif /* ! MAC_OSX */
3367 /* Return the path to the directory in which Emacs can create
3368 temporary files. The MacOS "temporary items" directory cannot be
3369 used because it removes the file written by a process when it
3370 exits. In that sense it's more like "/dev/null" than "/tmp" (but
3371 again not exactly). And of course Emacs needs to read back the
3372 files written by its subprocesses. So here we write the files to a
3373 directory "Emacs" in the Preferences Folder. This directory is
3374 created if it does not exist. */
3377 get_temp_dir_name ()
3379 static char *temp_dir_name
= NULL
;
3384 char unix_dir_name
[MAXPATHLEN
+1];
3387 /* Cache directory name with pointer temp_dir_name.
3388 Look for it only the first time. */
3391 err
= FindFolder (kOnSystemDisk
, kPreferencesFolderType
, kCreateFolder
,
3392 &vol_ref_num
, &dir_id
);
3396 if (!path_from_vol_dir_name (full_path
, 255, vol_ref_num
, dir_id
, "\p"))
3399 if (strlen (full_path
) + 6 <= MAXPATHLEN
)
3400 strcat (full_path
, "Emacs:");
3404 if (!mac_to_posix_pathname (full_path
, unix_dir_name
, MAXPATHLEN
+1))
3407 dir
= opendir (unix_dir_name
); /* check whether temp directory exists */
3410 else if (mkdir (unix_dir_name
, 0700) != 0) /* create it if not */
3413 temp_dir_name
= (char *) malloc (strlen (unix_dir_name
) + 1);
3414 strcpy (temp_dir_name
, unix_dir_name
);
3417 return temp_dir_name
;
3422 /* Allocate and construct an array of pointers to strings from a list
3423 of strings stored in a 'STR#' resource. The returned pointer array
3424 is stored in the style of argv and environ: if the 'STR#' resource
3425 contains numString strings, a pointer array with numString+1
3426 elements is returned in which the last entry contains a null
3427 pointer. The pointer to the pointer array is passed by pointer in
3428 parameter t. The resource ID of the 'STR#' resource is passed in
3429 parameter StringListID.
3433 get_string_list (char ***t
, short string_list_id
)
3439 h
= GetResource ('STR#', string_list_id
);
3444 num_strings
= * (short *) p
;
3446 *t
= (char **) malloc (sizeof (char *) * (num_strings
+ 1));
3447 for (i
= 0; i
< num_strings
; i
++)
3449 short length
= *p
++;
3450 (*t
)[i
] = (char *) malloc (length
+ 1);
3451 strncpy ((*t
)[i
], p
, length
);
3452 (*t
)[i
][length
] = '\0';
3455 (*t
)[num_strings
] = 0;
3460 /* Return no string in case GetResource fails. Bug fixed by
3461 Ikegami Tsutomu. Caused MPW build to crash without sym -on
3462 option (no sym -on implies -opt local). */
3463 *t
= (char **) malloc (sizeof (char *));
3470 get_path_to_system_folder ()
3476 static char system_folder_unix_name
[MAXPATHLEN
+1];
3479 err
= FindFolder (kOnSystemDisk
, kSystemFolderType
, kDontCreateFolder
,
3480 &vol_ref_num
, &dir_id
);
3484 if (!path_from_vol_dir_name (full_path
, 255, vol_ref_num
, dir_id
, "\p"))
3487 if (!mac_to_posix_pathname (full_path
, system_folder_unix_name
,
3491 return system_folder_unix_name
;
3497 #define ENVIRON_STRING_LIST_ID 128
3499 /* Get environment variable definitions from STR# resource. */
3506 get_string_list (&environ
, ENVIRON_STRING_LIST_ID
);
3512 /* Make HOME directory the one Emacs starts up in if not specified
3514 if (getenv ("HOME") == NULL
)
3516 environ
= (char **) realloc (environ
, sizeof (char *) * (i
+ 2));
3519 environ
[i
] = (char *) malloc (strlen (my_passwd_dir
) + 6);
3522 strcpy (environ
[i
], "HOME=");
3523 strcat (environ
[i
], my_passwd_dir
);
3530 /* Make HOME directory the one Emacs starts up in if not specified
3532 if (getenv ("MAIL") == NULL
)
3534 environ
= (char **) realloc (environ
, sizeof (char *) * (i
+ 2));
3537 char * path_to_system_folder
= get_path_to_system_folder ();
3538 environ
[i
] = (char *) malloc (strlen (path_to_system_folder
) + 22);
3541 strcpy (environ
[i
], "MAIL=");
3542 strcat (environ
[i
], path_to_system_folder
);
3543 strcat (environ
[i
], "Eudora Folder/In");
3551 /* Return the value of the environment variable NAME. */
3554 getenv (const char *name
)
3556 int length
= strlen(name
);
3559 for (e
= environ
; *e
!= 0; e
++)
3560 if (strncmp(*e
, name
, length
) == 0 && (*e
)[length
] == '=')
3561 return &(*e
)[length
+ 1];
3563 if (strcmp (name
, "TMPDIR") == 0)
3564 return get_temp_dir_name ();
3571 /* see Interfaces&Libraries:Interfaces:CIncludes:signal.h */
3572 char *sys_siglist
[] =
3574 "Zero is not a signal!!!",
3576 "Interactive user interrupt", /* 2 */ "?",
3577 "Floating point exception", /* 4 */ "?", "?", "?",
3578 "Illegal instruction", /* 8 */ "?", "?", "?", "?", "?", "?", "?",
3579 "Segment violation", /* 16 */ "?", "?", "?", "?", "?", "?", "?",
3580 "?", "?", "?", "?", "?", "?", "?", "?",
3584 char *sys_siglist
[] =
3586 "Zero is not a signal!!!",
3588 "Floating point exception",
3589 "Illegal instruction",
3590 "Interactive user interrupt",
3591 "Segment violation",
3594 #else /* not __MRC__ and not __MWERKS__ */
3596 #endif /* not __MRC__ and not __MWERKS__ */
3599 #include <utsname.h>
3602 uname (struct utsname
*name
)
3605 system_name
= GetString (-16413); /* IM - Resource Manager Reference */
3608 BlockMove (*system_name
, name
->nodename
, (*system_name
)[0]+1);
3609 p2cstr (name
->nodename
);
3617 /* Event class of HLE sent to subprocess. */
3618 const OSType kEmacsSubprocessSend
= 'ESND';
3620 /* Event class of HLE sent back from subprocess. */
3621 const OSType kEmacsSubprocessReply
= 'ERPY';
3625 mystrchr (char *s
, char c
)
3627 while (*s
&& *s
!= c
)
3655 mystrcpy (char *to
, char *from
)
3667 /* Start a Mac subprocess. Arguments for it is passed in argv (null
3668 terminated). The process should run with the default directory
3669 "workdir", read input from "infn", and write output and error to
3670 "outfn" and "errfn", resp. The Process Manager call
3671 LaunchApplication is used to start the subprocess. We use high
3672 level events as the mechanism to pass arguments to the subprocess
3673 and to make Emacs wait for the subprocess to terminate and pass
3674 back a result code. The bulk of the code here packs the arguments
3675 into one message to be passed together with the high level event.
3676 Emacs also sometimes starts a subprocess using a shell to perform
3677 wildcard filename expansion. Since we don't really have a shell on
3678 the Mac, this case is detected and the starting of the shell is
3679 by-passed. We really need to add code here to do filename
3680 expansion to support such functionality.
3682 We can't use this strategy in Carbon because the High Level Event
3683 APIs are not available. */
3686 run_mac_command (argv
, workdir
, infn
, outfn
, errfn
)
3687 unsigned char **argv
;
3688 const char *workdir
;
3689 const char *infn
, *outfn
, *errfn
;
3691 #if TARGET_API_MAC_CARBON
3693 #else /* not TARGET_API_MAC_CARBON */
3694 char macappname
[MAXPATHLEN
+1], macworkdir
[MAXPATHLEN
+1];
3695 char macinfn
[MAXPATHLEN
+1], macoutfn
[MAXPATHLEN
+1], macerrfn
[MAXPATHLEN
+1];
3696 int paramlen
, argc
, newargc
, j
, retries
;
3697 char **newargv
, *param
, *p
;
3700 LaunchParamBlockRec lpbr
;
3701 EventRecord send_event
, reply_event
;
3702 RgnHandle cursor_region_handle
;
3704 unsigned long ref_con
, len
;
3706 if (posix_to_mac_pathname (workdir
, macworkdir
, MAXPATHLEN
+1) == 0)
3708 if (posix_to_mac_pathname (infn
, macinfn
, MAXPATHLEN
+1) == 0)
3710 if (posix_to_mac_pathname (outfn
, macoutfn
, MAXPATHLEN
+1) == 0)
3712 if (posix_to_mac_pathname (errfn
, macerrfn
, MAXPATHLEN
+1) == 0)
3715 paramlen
= strlen (macworkdir
) + strlen (macinfn
) + strlen (macoutfn
)
3716 + strlen (macerrfn
) + 4; /* count nulls at end of strings */
3725 /* If a subprocess is invoked with a shell, we receive 3 arguments
3726 of the form: "<path to emacs bins>/sh" "-c" "<path to emacs
3727 bins>/<command> <command args>" */
3728 j
= strlen (argv
[0]);
3729 if (j
>= 3 && strcmp (argv
[0]+j
-3, "/sh") == 0
3730 && argc
== 3 && strcmp (argv
[1], "-c") == 0)
3732 char *command
, *t
, tempmacpathname
[MAXPATHLEN
+1];
3734 /* The arguments for the command in argv[2] are separated by
3735 spaces. Count them and put the count in newargc. */
3736 command
= (char *) alloca (strlen (argv
[2])+2);
3737 strcpy (command
, argv
[2]);
3738 if (command
[strlen (command
) - 1] != ' ')
3739 strcat (command
, " ");
3743 t
= mystrchr (t
, ' ');
3747 t
= mystrchr (t
+1, ' ');
3750 newargv
= (char **) alloca (sizeof (char *) * newargc
);
3753 for (j
= 0; j
< newargc
; j
++)
3755 newargv
[j
] = (char *) alloca (strlen (t
) + 1);
3756 mystrcpy (newargv
[j
], t
);
3759 paramlen
+= strlen (newargv
[j
]) + 1;
3762 if (strncmp (newargv
[0], "~emacs/", 7) == 0)
3764 if (posix_to_mac_pathname (newargv
[0], tempmacpathname
, MAXPATHLEN
+1)
3769 { /* sometimes Emacs call "sh" without a path for the command */
3771 char *t
= (char *) alloca (strlen (newargv
[0]) + 7 + 1);
3772 strcpy (t
, "~emacs/");
3773 strcat (t
, newargv
[0]);
3776 openp (Vexec_path
, build_string (newargv
[0]), Vexec_suffixes
, &path
,
3777 make_number (X_OK
));
3781 if (posix_to_mac_pathname (SDATA (path
), tempmacpathname
,
3785 strcpy (macappname
, tempmacpathname
);
3789 if (posix_to_mac_pathname (argv
[0], macappname
, MAXPATHLEN
+1) == 0)
3792 newargv
= (char **) alloca (sizeof (char *) * argc
);
3794 for (j
= 1; j
< argc
; j
++)
3796 if (strncmp (argv
[j
], "~emacs/", 7) == 0)
3798 char *t
= strchr (argv
[j
], ' ');
3801 char tempcmdname
[MAXPATHLEN
+1], tempmaccmdname
[MAXPATHLEN
+1];
3802 strncpy (tempcmdname
, argv
[j
], t
-argv
[j
]);
3803 tempcmdname
[t
-argv
[j
]] = '\0';
3804 if (posix_to_mac_pathname (tempcmdname
, tempmaccmdname
,
3807 newargv
[j
] = (char *) alloca (strlen (tempmaccmdname
)
3809 strcpy (newargv
[j
], tempmaccmdname
);
3810 strcat (newargv
[j
], t
);
3814 char tempmaccmdname
[MAXPATHLEN
+1];
3815 if (posix_to_mac_pathname (argv
[j
], tempmaccmdname
,
3818 newargv
[j
] = (char *) alloca (strlen (tempmaccmdname
)+1);
3819 strcpy (newargv
[j
], tempmaccmdname
);
3823 newargv
[j
] = argv
[j
];
3824 paramlen
+= strlen (newargv
[j
]) + 1;
3828 /* After expanding all the arguments, we now know the length of the
3829 parameter block to be sent to the subprocess as a message
3830 attached to the HLE. */
3831 param
= (char *) malloc (paramlen
+ 1);
3837 /* first byte of message contains number of arguments for command */
3838 strcpy (p
, macworkdir
);
3839 p
+= strlen (macworkdir
);
3841 /* null terminate strings sent so it's possible to use strcpy over there */
3842 strcpy (p
, macinfn
);
3843 p
+= strlen (macinfn
);
3845 strcpy (p
, macoutfn
);
3846 p
+= strlen (macoutfn
);
3848 strcpy (p
, macerrfn
);
3849 p
+= strlen (macerrfn
);
3851 for (j
= 1; j
< newargc
; j
++)
3853 strcpy (p
, newargv
[j
]);
3854 p
+= strlen (newargv
[j
]);
3858 c2pstr (macappname
);
3860 iErr
= FSMakeFSSpec (0, 0, macappname
, &spec
);
3868 lpbr
.launchBlockID
= extendedBlock
;
3869 lpbr
.launchEPBLength
= extendedBlockLen
;
3870 lpbr
.launchControlFlags
= launchContinue
+ launchNoFileFlags
;
3871 lpbr
.launchAppSpec
= &spec
;
3872 lpbr
.launchAppParameters
= NULL
;
3874 iErr
= LaunchApplication (&lpbr
); /* call the subprocess */
3881 send_event
.what
= kHighLevelEvent
;
3882 send_event
.message
= kEmacsSubprocessSend
;
3883 /* Event ID stored in "where" unused */
3886 /* OS may think current subprocess has terminated if previous one
3887 terminated recently. */
3890 iErr
= PostHighLevelEvent (&send_event
, &lpbr
.launchProcessSN
, 0, param
,
3891 paramlen
+ 1, receiverIDisPSN
);
3893 while (iErr
== sessClosedErr
&& retries
-- > 0);
3901 cursor_region_handle
= NewRgn ();
3903 /* Wait for the subprocess to finish, when it will send us a ERPY
3904 high level event. */
3906 if (WaitNextEvent (highLevelEventMask
, &reply_event
, 180,
3907 cursor_region_handle
)
3908 && reply_event
.message
== kEmacsSubprocessReply
)
3911 /* The return code is sent through the refCon */
3912 iErr
= AcceptHighLevelEvent (&targ
, &ref_con
, NULL
, &len
);
3915 DisposeHandle ((Handle
) cursor_region_handle
);
3920 DisposeHandle ((Handle
) cursor_region_handle
);
3924 #endif /* not TARGET_API_MAC_CARBON */
3929 opendir (const char *dirname
)
3931 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
3932 char mac_pathname
[MAXPATHLEN
+1], vol_name
[MAXPATHLEN
+1];
3936 int len
, vol_name_len
;
3938 if (find_true_pathname (dirname
, true_pathname
, MAXPATHLEN
+1) == -1)
3941 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
3943 fully_resolved_name
[len
] = '\0';
3945 strcpy (fully_resolved_name
, true_pathname
);
3947 dirp
= (DIR *) malloc (sizeof(DIR));
3951 /* Handle special case when dirname is "/": sets up for readir to
3952 get all mount volumes. */
3953 if (strcmp (fully_resolved_name
, "/") == 0)
3955 dirp
->getting_volumes
= 1; /* special all mounted volumes DIR struct */
3956 dirp
->current_index
= 1; /* index for first volume */
3960 /* Handle typical cases: not accessing all mounted volumes. */
3961 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
3964 /* Emacs calls opendir without the trailing '/', Mac needs trailing ':' */
3965 len
= strlen (mac_pathname
);
3966 if (mac_pathname
[len
- 1] != ':' && len
< MAXPATHLEN
)
3967 strcat (mac_pathname
, ":");
3969 /* Extract volume name */
3970 vol_name_len
= strchr (mac_pathname
, ':') - mac_pathname
;
3971 strncpy (vol_name
, mac_pathname
, vol_name_len
);
3972 vol_name
[vol_name_len
] = '\0';
3973 strcat (vol_name
, ":");
3975 c2pstr (mac_pathname
);
3976 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
3977 /* using full pathname so vRefNum and DirID ignored */
3978 cipb
.hFileInfo
.ioVRefNum
= 0;
3979 cipb
.hFileInfo
.ioDirID
= 0;
3980 cipb
.hFileInfo
.ioFDirIndex
= 0;
3981 /* set to 0 to get information about specific dir or file */
3983 errno
= PBGetCatInfo (&cipb
, false);
3990 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x10)) /* bit 4 = 1 for directories */
3991 return 0; /* not a directory */
3993 dirp
->dir_id
= cipb
.dirInfo
.ioDrDirID
; /* used later in readdir */
3994 dirp
->getting_volumes
= 0;
3995 dirp
->current_index
= 1; /* index for first file/directory */
3998 vpb
.ioNamePtr
= vol_name
;
3999 /* using full pathname so vRefNum and DirID ignored */
4001 vpb
.ioVolIndex
= -1;
4002 errno
= PBHGetVInfo ((union HParamBlockRec
*) &vpb
, false);
4009 dirp
->vol_ref_num
= vpb
.ioVRefNum
;
4026 HParamBlockRec hpblock
;
4028 static struct dirent s_dirent
;
4029 static Str255 s_name
;
4033 /* Handle the root directory containing the mounted volumes. Call
4034 PBHGetVInfo specifying an index to obtain the info for a volume.
4035 PBHGetVInfo returns an error when it receives an index beyond the
4036 last volume, at which time we should return a nil dirent struct
4038 if (dp
->getting_volumes
)
4040 hpblock
.volumeParam
.ioNamePtr
= s_name
;
4041 hpblock
.volumeParam
.ioVRefNum
= 0;
4042 hpblock
.volumeParam
.ioVolIndex
= dp
->current_index
;
4044 errno
= PBHGetVInfo (&hpblock
, false);
4052 strcat (s_name
, "/"); /* need "/" for stat to work correctly */
4054 dp
->current_index
++;
4056 s_dirent
.d_ino
= hpblock
.volumeParam
.ioVRefNum
;
4057 s_dirent
.d_name
= s_name
;
4063 cipb
.hFileInfo
.ioVRefNum
= dp
->vol_ref_num
;
4064 cipb
.hFileInfo
.ioNamePtr
= s_name
;
4065 /* location to receive filename returned */
4067 /* return only visible files */
4071 cipb
.hFileInfo
.ioDirID
= dp
->dir_id
;
4072 /* directory ID found by opendir */
4073 cipb
.hFileInfo
.ioFDirIndex
= dp
->current_index
;
4075 errno
= PBGetCatInfo (&cipb
, false);
4082 /* insist on a visible entry */
4083 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* directory? */
4084 done
= !(cipb
.dirInfo
.ioDrUsrWds
.frFlags
& fInvisible
);
4086 done
= !(cipb
.hFileInfo
.ioFlFndrInfo
.fdFlags
& fInvisible
);
4088 dp
->current_index
++;
4101 s_dirent
.d_ino
= cipb
.dirInfo
.ioDrDirID
;
4102 /* value unimportant: non-zero for valid file */
4103 s_dirent
.d_name
= s_name
;
4113 char mac_pathname
[MAXPATHLEN
+1];
4114 Str255 directory_name
;
4118 if (path_from_vol_dir_name (mac_pathname
, 255, 0, 0, "\p") == 0)
4121 if (mac_to_posix_pathname (mac_pathname
, path
, MAXPATHLEN
+1) == 0)
4127 #endif /* ! MAC_OSX */
4131 initialize_applescript ()
4136 /* if open fails, as_scripting_component is set to NULL. Its
4137 subsequent use in OSA calls will fail with badComponentInstance
4139 as_scripting_component
= OpenDefaultComponent (kOSAComponentType
,
4140 kAppleScriptSubtype
);
4142 null_desc
.descriptorType
= typeNull
;
4143 null_desc
.dataHandle
= 0;
4144 osaerror
= OSAMakeContext (as_scripting_component
, &null_desc
,
4145 kOSANullScript
, &as_script_context
);
4147 as_script_context
= kOSANullScript
;
4148 /* use default context if create fails */
4153 terminate_applescript()
4155 OSADispose (as_scripting_component
, as_script_context
);
4156 CloseComponent (as_scripting_component
);
4159 /* Convert a lisp string to the 4 byte character code. */
4162 mac_get_code_from_arg(Lisp_Object arg
, OSType defCode
)
4171 /* check type string */
4173 if (SBYTES (arg
) != 4)
4175 error ("Wrong argument: need string of length 4 for code");
4177 result
= EndianU32_BtoN (*((UInt32
*) SDATA (arg
)));
4182 /* Convert the 4 byte character code into a 4 byte string. */
4185 mac_get_object_from_code(OSType defCode
)
4187 UInt32 code
= EndianU32_NtoB (defCode
);
4189 return make_unibyte_string ((char *)&code
, 4);
4193 DEFUN ("mac-get-file-creator", Fmac_get_file_creator
, Smac_get_file_creator
, 1, 1, 0,
4194 doc
: /* Get the creator 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
)->fileCreator
);
4236 result
= mac_get_object_from_code (finder_info
.fdCreator
);
4241 if (status
!= noErr
) {
4242 error ("Error while getting file information.");
4247 DEFUN ("mac-get-file-type", Fmac_get_file_type
, Smac_get_file_type
, 1, 1, 0,
4248 doc
: /* Get the type code of FILENAME as a four character string. */)
4250 Lisp_Object filename
;
4258 Lisp_Object result
= Qnil
;
4259 CHECK_STRING (filename
);
4261 if (NILP(Ffile_exists_p(filename
)) || !NILP(Ffile_directory_p(filename
))) {
4264 filename
= Fexpand_file_name (filename
, Qnil
);
4268 status
= FSPathMakeRef(SDATA(ENCODE_FILE(filename
)), &fref
, NULL
);
4270 status
= posix_pathname_to_fsspec (SDATA (ENCODE_FILE (filename
)), &fss
);
4273 if (status
== noErr
)
4276 FSCatalogInfo catalogInfo
;
4278 status
= FSGetCatalogInfo(&fref
, kFSCatInfoFinderInfo
,
4279 &catalogInfo
, NULL
, NULL
, NULL
);
4283 status
= FSpGetFInfo (&fss
, &finder_info
);
4285 if (status
== noErr
)
4288 result
= mac_get_object_from_code(((FileInfo
*)&catalogInfo
.finderInfo
)->fileType
);
4290 result
= mac_get_object_from_code (finder_info
.fdType
);
4295 if (status
!= noErr
) {
4296 error ("Error while getting file information.");
4301 DEFUN ("mac-set-file-creator", Fmac_set_file_creator
, Smac_set_file_creator
, 1, 2, 0,
4302 doc
: /* Set creator code of file FILENAME to CODE.
4303 If non-nil, CODE must be a 4-character string. Otherwise, 'EMAx' is
4304 assumed. Return non-nil if successful. */)
4306 Lisp_Object filename
, code
;
4315 CHECK_STRING (filename
);
4317 cCode
= mac_get_code_from_arg(code
, MAC_EMACS_CREATOR_CODE
);
4319 if (NILP(Ffile_exists_p(filename
)) || !NILP(Ffile_directory_p(filename
))) {
4322 filename
= Fexpand_file_name (filename
, Qnil
);
4326 status
= FSPathMakeRef(SDATA(ENCODE_FILE(filename
)), &fref
, NULL
);
4328 status
= posix_pathname_to_fsspec (SDATA (ENCODE_FILE (filename
)), &fss
);
4331 if (status
== noErr
)
4334 FSCatalogInfo catalogInfo
;
4336 status
= FSGetCatalogInfo(&fref
, kFSCatInfoFinderInfo
,
4337 &catalogInfo
, NULL
, NULL
, &parentDir
);
4341 status
= FSpGetFInfo (&fss
, &finder_info
);
4343 if (status
== noErr
)
4346 ((FileInfo
*)&catalogInfo
.finderInfo
)->fileCreator
= cCode
;
4347 status
= FSSetCatalogInfo(&fref
, kFSCatInfoFinderInfo
, &catalogInfo
);
4348 /* TODO: on Mac OS 10.2, we need to touch the parent dir, FNNotify? */
4350 finder_info
.fdCreator
= cCode
;
4351 status
= FSpSetFInfo (&fss
, &finder_info
);
4356 if (status
!= noErr
) {
4357 error ("Error while setting creator information.");
4362 DEFUN ("mac-set-file-type", Fmac_set_file_type
, Smac_set_file_type
, 2, 2, 0,
4363 doc
: /* Set file code of file FILENAME to CODE.
4364 CODE must be a 4-character string. Return non-nil if successful. */)
4366 Lisp_Object filename
, code
;
4375 CHECK_STRING (filename
);
4377 cCode
= mac_get_code_from_arg(code
, 0); /* Default to empty code*/
4379 if (NILP(Ffile_exists_p(filename
)) || !NILP(Ffile_directory_p(filename
))) {
4382 filename
= Fexpand_file_name (filename
, Qnil
);
4386 status
= FSPathMakeRef(SDATA(ENCODE_FILE(filename
)), &fref
, NULL
);
4388 status
= posix_pathname_to_fsspec (SDATA (ENCODE_FILE (filename
)), &fss
);
4391 if (status
== noErr
)
4394 FSCatalogInfo catalogInfo
;
4396 status
= FSGetCatalogInfo(&fref
, kFSCatInfoFinderInfo
,
4397 &catalogInfo
, NULL
, NULL
, &parentDir
);
4401 status
= FSpGetFInfo (&fss
, &finder_info
);
4403 if (status
== noErr
)
4406 ((FileInfo
*)&catalogInfo
.finderInfo
)->fileType
= cCode
;
4407 status
= FSSetCatalogInfo(&fref
, kFSCatInfoFinderInfo
, &catalogInfo
);
4408 /* TODO: on Mac OS 10.2, we need to touch the parent dir, FNNotify? */
4410 finder_info
.fdType
= cCode
;
4411 status
= FSpSetFInfo (&fss
, &finder_info
);
4416 if (status
!= noErr
) {
4417 error ("Error while setting creator information.");
4423 /* Compile and execute the AppleScript SCRIPT and return the error
4424 status as function value. A zero is returned if compilation and
4425 execution is successful, in which case *RESULT is set to a Lisp
4426 string containing the resulting script value. Otherwise, the Mac
4427 error code is returned and *RESULT is set to an error Lisp string.
4428 For documentation on the MacOS scripting architecture, see Inside
4429 Macintosh - Interapplication Communications: Scripting
4433 do_applescript (script
, result
)
4434 Lisp_Object script
, *result
;
4436 AEDesc script_desc
, result_desc
, error_desc
, *desc
= NULL
;
4442 if (!as_scripting_component
)
4443 initialize_applescript();
4445 error
= AECreateDesc (typeChar
, SDATA (script
), SBYTES (script
),
4450 osaerror
= OSADoScript (as_scripting_component
, &script_desc
, kOSANullScript
,
4451 typeChar
, kOSAModeNull
, &result_desc
);
4453 if (osaerror
== noErr
)
4454 /* success: retrieve resulting script value */
4455 desc
= &result_desc
;
4456 else if (osaerror
== errOSAScriptError
)
4457 /* error executing AppleScript: retrieve error message */
4458 if (!OSAScriptError (as_scripting_component
, kOSAErrorMessage
, typeChar
,
4464 #if TARGET_API_MAC_CARBON
4465 *result
= make_uninit_string (AEGetDescDataSize (desc
));
4466 AEGetDescData (desc
, SDATA (*result
), SBYTES (*result
));
4467 #else /* not TARGET_API_MAC_CARBON */
4468 *result
= make_uninit_string (GetHandleSize (desc
->dataHandle
));
4469 memcpy (SDATA (*result
), *(desc
->dataHandle
), SBYTES (*result
));
4470 #endif /* not TARGET_API_MAC_CARBON */
4471 AEDisposeDesc (desc
);
4474 AEDisposeDesc (&script_desc
);
4480 DEFUN ("do-applescript", Fdo_applescript
, Sdo_applescript
, 1, 1, 0,
4481 doc
: /* Compile and execute AppleScript SCRIPT and return the result.
4482 If compilation and execution are successful, the resulting script
4483 value is returned as a string. Otherwise the function aborts and
4484 displays the error message returned by the AppleScript scripting
4492 CHECK_STRING (script
);
4495 status
= do_applescript (script
, &result
);
4499 else if (!STRINGP (result
))
4500 error ("AppleScript error %d", status
);
4502 error ("%s", SDATA (result
));
4506 DEFUN ("mac-file-name-to-posix", Fmac_file_name_to_posix
,
4507 Smac_file_name_to_posix
, 1, 1, 0,
4508 doc
: /* Convert Macintosh FILENAME to Posix form. */)
4510 Lisp_Object filename
;
4512 char posix_filename
[MAXPATHLEN
+1];
4514 CHECK_STRING (filename
);
4516 if (mac_to_posix_pathname (SDATA (filename
), posix_filename
, MAXPATHLEN
))
4517 return build_string (posix_filename
);
4523 DEFUN ("posix-file-name-to-mac", Fposix_file_name_to_mac
,
4524 Sposix_file_name_to_mac
, 1, 1, 0,
4525 doc
: /* Convert Posix FILENAME to Mac form. */)
4527 Lisp_Object filename
;
4529 char mac_filename
[MAXPATHLEN
+1];
4531 CHECK_STRING (filename
);
4533 if (posix_to_mac_pathname (SDATA (filename
), mac_filename
, MAXPATHLEN
))
4534 return build_string (mac_filename
);
4540 DEFUN ("mac-coerce-ae-data", Fmac_coerce_ae_data
, Smac_coerce_ae_data
, 3, 3, 0,
4541 doc
: /* Coerce Apple event data SRC-DATA of type SRC-TYPE to DST-TYPE.
4542 Each type should be a string of length 4 or the symbol
4543 `undecoded-file-name'. */)
4544 (src_type
, src_data
, dst_type
)
4545 Lisp_Object src_type
, src_data
, dst_type
;
4548 Lisp_Object result
= Qnil
;
4549 DescType src_desc_type
, dst_desc_type
;
4552 CHECK_STRING (src_data
);
4553 if (EQ (src_type
, Qundecoded_file_name
))
4554 src_desc_type
= TYPE_FILE_NAME
;
4556 src_desc_type
= mac_get_code_from_arg (src_type
, 0);
4558 if (EQ (dst_type
, Qundecoded_file_name
))
4559 dst_desc_type
= TYPE_FILE_NAME
;
4561 dst_desc_type
= mac_get_code_from_arg (dst_type
, 0);
4564 err
= AECoercePtr (src_desc_type
, SDATA (src_data
), SBYTES (src_data
),
4565 dst_desc_type
, &dst_desc
);
4568 result
= Fcdr (mac_aedesc_to_lisp (&dst_desc
));
4569 AEDisposeDesc (&dst_desc
);
4577 #if TARGET_API_MAC_CARBON
4578 static Lisp_Object Qxml
, Qmime_charset
;
4579 static Lisp_Object QNFD
, QNFKD
, QNFC
, QNFKC
, QHFS_plus_D
, QHFS_plus_C
;
4581 DEFUN ("mac-get-preference", Fmac_get_preference
, Smac_get_preference
, 1, 4, 0,
4582 doc
: /* Return the application preference value for KEY.
4583 KEY is either a string specifying a preference key, or a list of key
4584 strings. If it is a list, the (i+1)-th element is used as a key for
4585 the CFDictionary value obtained by the i-th element. Return nil if
4586 lookup is failed at some stage.
4588 Optional arg APPLICATION is an application ID string. If omitted or
4589 nil, that stands for the current application.
4591 Optional arg FORMAT specifies the data format of the return value. If
4592 omitted or nil, each Core Foundation object is converted into a
4593 corresponding Lisp object as follows:
4595 Core Foundation Lisp Tag
4596 ------------------------------------------------------------
4597 CFString Multibyte string string
4598 CFNumber Integer or float number
4599 CFBoolean Symbol (t or nil) boolean
4600 CFDate List of three integers date
4601 (cf. `current-time')
4602 CFData Unibyte string data
4603 CFArray Vector array
4604 CFDictionary Alist or hash table dictionary
4605 (depending on HASH-BOUND)
4607 If it is t, a symbol that represents the type of the original Core
4608 Foundation object is prepended. If it is `xml', the value is returned
4609 as an XML representation.
4611 Optional arg HASH-BOUND specifies which kinds of the list objects,
4612 alists or hash tables, are used as the targets of the conversion from
4613 CFDictionary. If HASH-BOUND is a negative integer or nil, always
4614 generate alists. If HASH-BOUND >= 0, generate an alist if the number
4615 of keys in the dictionary is smaller than HASH-BOUND, and a hash table
4617 (key
, application
, format
, hash_bound
)
4618 Lisp_Object key
, application
, format
, hash_bound
;
4620 CFStringRef app_id
, key_str
;
4621 CFPropertyListRef app_plist
= NULL
, plist
;
4622 Lisp_Object result
= Qnil
, tmp
;
4623 struct gcpro gcpro1
, gcpro2
;
4626 key
= Fcons (key
, Qnil
);
4630 for (tmp
= key
; CONSP (tmp
); tmp
= XCDR (tmp
))
4631 CHECK_STRING_CAR (tmp
);
4632 CHECK_LIST_END (tmp
, key
);
4634 if (!NILP (application
))
4635 CHECK_STRING (application
);
4636 CHECK_SYMBOL (format
);
4637 if (!NILP (hash_bound
))
4638 CHECK_NUMBER (hash_bound
);
4640 GCPRO2 (key
, format
);
4644 app_id
= kCFPreferencesCurrentApplication
;
4645 if (!NILP (application
))
4647 app_id
= cfstring_create_with_string (application
);
4651 if (!CFPreferencesAppSynchronize (app_id
))
4654 key_str
= cfstring_create_with_string (XCAR (key
));
4655 if (key_str
== NULL
)
4657 app_plist
= CFPreferencesCopyAppValue (key_str
, app_id
);
4658 CFRelease (key_str
);
4659 if (app_plist
== NULL
)
4663 for (key
= XCDR (key
); CONSP (key
); key
= XCDR (key
))
4665 if (CFGetTypeID (plist
) != CFDictionaryGetTypeID ())
4667 key_str
= cfstring_create_with_string (XCAR (key
));
4668 if (key_str
== NULL
)
4670 plist
= CFDictionaryGetValue (plist
, key_str
);
4671 CFRelease (key_str
);
4678 if (EQ (format
, Qxml
))
4680 CFDataRef data
= CFPropertyListCreateXMLData (NULL
, plist
);
4683 result
= cfdata_to_lisp (data
);
4688 cfproperty_list_to_lisp (plist
, EQ (format
, Qt
),
4689 NILP (hash_bound
) ? -1 : XINT (hash_bound
));
4694 CFRelease (app_plist
);
4705 static CFStringEncoding
4706 get_cfstring_encoding_from_lisp (obj
)
4709 CFStringRef iana_name
;
4710 CFStringEncoding encoding
= kCFStringEncodingInvalidId
;
4713 return kCFStringEncodingUnicode
;
4718 if (SYMBOLP (obj
) && !NILP (Fcoding_system_p (obj
)))
4720 Lisp_Object coding_spec
, plist
;
4722 coding_spec
= Fget (obj
, Qcoding_system
);
4723 plist
= XVECTOR (coding_spec
)->contents
[3];
4724 obj
= Fplist_get (XVECTOR (coding_spec
)->contents
[3], Qmime_charset
);
4728 obj
= SYMBOL_NAME (obj
);
4732 iana_name
= cfstring_create_with_string (obj
);
4735 encoding
= CFStringConvertIANACharSetNameToEncoding (iana_name
);
4736 CFRelease (iana_name
);
4743 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
4745 cfstring_create_normalized (str
, symbol
)
4750 TextEncodingVariant variant
;
4751 float initial_mag
= 0.0;
4752 CFStringRef result
= NULL
;
4754 if (EQ (symbol
, QNFD
))
4755 form
= kCFStringNormalizationFormD
;
4756 else if (EQ (symbol
, QNFKD
))
4757 form
= kCFStringNormalizationFormKD
;
4758 else if (EQ (symbol
, QNFC
))
4759 form
= kCFStringNormalizationFormC
;
4760 else if (EQ (symbol
, QNFKC
))
4761 form
= kCFStringNormalizationFormKC
;
4762 else if (EQ (symbol
, QHFS_plus_D
))
4764 variant
= kUnicodeHFSPlusDecompVariant
;
4767 else if (EQ (symbol
, QHFS_plus_C
))
4769 variant
= kUnicodeHFSPlusCompVariant
;
4775 CFMutableStringRef mut_str
= CFStringCreateMutableCopy (NULL
, 0, str
);
4779 CFStringNormalize (mut_str
, form
);
4783 else if (initial_mag
> 0.0)
4785 UnicodeToTextInfo uni
= NULL
;
4788 UniChar
*in_text
, *buffer
= NULL
, *out_buf
= NULL
;
4789 OSStatus err
= noErr
;
4790 ByteCount out_read
, out_size
, out_len
;
4792 map
.unicodeEncoding
= CreateTextEncoding (kTextEncodingUnicodeDefault
,
4794 kTextEncodingDefaultFormat
);
4795 map
.otherEncoding
= CreateTextEncoding (kTextEncodingUnicodeDefault
,
4797 kTextEncodingDefaultFormat
);
4798 map
.mappingVersion
= kUnicodeUseLatestMapping
;
4800 length
= CFStringGetLength (str
);
4801 out_size
= (int)((float)length
* initial_mag
) * sizeof (UniChar
);
4805 in_text
= (UniChar
*)CFStringGetCharactersPtr (str
);
4806 if (in_text
== NULL
)
4808 buffer
= xmalloc (sizeof (UniChar
) * length
);
4809 CFStringGetCharacters (str
, CFRangeMake (0, length
), buffer
);
4814 err
= CreateUnicodeToTextInfo (&map
, &uni
);
4815 while (err
== noErr
)
4817 out_buf
= xmalloc (out_size
);
4818 err
= ConvertFromUnicodeToText (uni
, length
* sizeof (UniChar
),
4820 kUnicodeDefaultDirectionMask
,
4821 0, NULL
, NULL
, NULL
,
4822 out_size
, &out_read
, &out_len
,
4824 if (err
== noErr
&& out_read
< length
* sizeof (UniChar
))
4833 result
= CFStringCreateWithCharacters (NULL
, out_buf
,
4834 out_len
/ sizeof (UniChar
));
4836 DisposeUnicodeToTextInfo (&uni
);
4852 DEFUN ("mac-code-convert-string", Fmac_code_convert_string
, Smac_code_convert_string
, 3, 4, 0,
4853 doc
: /* Convert STRING from SOURCE encoding to TARGET encoding.
4854 The conversion is performed using the converter provided by the system.
4855 Each encoding is specified by either a coding system symbol, a mime
4856 charset string, or an integer as a CFStringEncoding value. An encoding
4857 of nil means UTF-16 in native byte order, no byte order mark.
4858 On Mac OS X 10.2 and later, you can do Unicode Normalization by
4859 specifying the optional argument NORMALIZATION-FORM with a symbol NFD,
4860 NFKD, NFC, NFKC, HFS+D, or HFS+C.
4861 On successful conversion, return the result string, else return nil. */)
4862 (string
, source
, target
, normalization_form
)
4863 Lisp_Object string
, source
, target
, normalization_form
;
4865 Lisp_Object result
= Qnil
;
4866 struct gcpro gcpro1
, gcpro2
, gcpro3
, gcpro4
;
4867 CFStringEncoding src_encoding
, tgt_encoding
;
4868 CFStringRef str
= NULL
;
4870 CHECK_STRING (string
);
4871 if (!INTEGERP (source
) && !STRINGP (source
))
4872 CHECK_SYMBOL (source
);
4873 if (!INTEGERP (target
) && !STRINGP (target
))
4874 CHECK_SYMBOL (target
);
4875 CHECK_SYMBOL (normalization_form
);
4877 GCPRO4 (string
, source
, target
, normalization_form
);
4881 src_encoding
= get_cfstring_encoding_from_lisp (source
);
4882 tgt_encoding
= get_cfstring_encoding_from_lisp (target
);
4884 /* We really want string_to_unibyte, but since it doesn't exist yet, we
4885 use string_as_unibyte which works as well, except for the fact that
4886 it's too permissive (it doesn't check that the multibyte string only
4887 contain single-byte chars). */
4888 string
= Fstring_as_unibyte (string
);
4889 if (src_encoding
!= kCFStringEncodingInvalidId
4890 && tgt_encoding
!= kCFStringEncodingInvalidId
)
4891 str
= CFStringCreateWithBytes (NULL
, SDATA (string
), SBYTES (string
),
4892 src_encoding
, !NILP (source
));
4893 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
4896 CFStringRef saved_str
= str
;
4898 str
= cfstring_create_normalized (saved_str
, normalization_form
);
4899 CFRelease (saved_str
);
4904 CFIndex str_len
, buf_len
;
4906 str_len
= CFStringGetLength (str
);
4907 if (CFStringGetBytes (str
, CFRangeMake (0, str_len
), tgt_encoding
, 0,
4908 !NILP (target
), NULL
, 0, &buf_len
) == str_len
)
4910 result
= make_uninit_string (buf_len
);
4911 CFStringGetBytes (str
, CFRangeMake (0, str_len
), tgt_encoding
, 0,
4912 !NILP (target
), SDATA (result
), buf_len
, NULL
);
4924 DEFUN ("mac-process-hi-command", Fmac_process_hi_command
, Smac_process_hi_command
, 1, 1, 0,
4925 doc
: /* Send a HI command whose ID is COMMAND-ID to the command chain.
4926 COMMAND-ID must be a 4-character string. Some common command IDs are
4927 defined in the Carbon Event Manager. */)
4929 Lisp_Object command_id
;
4934 bzero (&command
, sizeof (HICommand
));
4935 command
.commandID
= mac_get_code_from_arg (command_id
, 0);
4938 err
= ProcessHICommand (&command
);
4942 error ("HI command (command ID: '%s') not handled.", SDATA (command_id
));
4947 #endif /* TARGET_API_MAC_CARBON */
4951 mac_get_system_locale ()
4959 lang
= GetScriptVariable (smSystemScript
, smScriptLang
);
4960 region
= GetScriptManagerVariable (smRegionCode
);
4961 err
= LocaleRefFromLangOrRegionCode (lang
, region
, &locale
);
4963 err
= LocaleRefGetPartString (locale
, kLocaleAllPartsMask
,
4966 return build_string (str
);
4974 extern int inhibit_window_system
;
4975 extern int noninteractive
;
4977 /* Unlike in X11, window events in Carbon do not come from sockets.
4978 So we cannot simply use `select' to monitor two kinds of inputs:
4979 window events and process outputs. We emulate such functionality
4980 by regarding fd 0 as the window event channel and simultaneously
4981 monitoring both kinds of input channels. It is implemented by
4982 dividing into some cases:
4983 1. The window event channel is not involved.
4985 2. Sockets are not involved.
4986 -> Use ReceiveNextEvent.
4987 3. [If SELECT_USE_CFSOCKET is set]
4988 Only the window event channel and socket read/write channels are
4989 involved, and timeout is not too short (greater than
4990 SELECT_TIMEOUT_THRESHOLD_RUNLOOP seconds).
4991 -> Create CFSocket for each socket and add it into the current
4992 event RunLoop so that the current event loop gets quit when
4993 the socket becomes ready. Then ReceiveNextEvent can wait for
4994 both kinds of inputs.
4996 -> Periodically poll the window input channel while repeatedly
4997 executing `select' with a short timeout
4998 (SELECT_POLLING_PERIOD_USEC microseconds). */
5000 #ifndef SELECT_USE_CFSOCKET
5001 #define SELECT_USE_CFSOCKET 1
5004 #define SELECT_POLLING_PERIOD_USEC 100000
5005 #if SELECT_USE_CFSOCKET
5006 #define SELECT_TIMEOUT_THRESHOLD_RUNLOOP 0.2
5009 socket_callback (s
, type
, address
, data
, info
)
5011 CFSocketCallBackType type
;
5016 int fd
= CFSocketGetNative (s
);
5017 SELECT_TYPE
*ofds
= (SELECT_TYPE
*)info
;
5019 if ((type
== kCFSocketReadCallBack
&& FD_ISSET (fd
, &ofds
[0]))
5020 || (type
== kCFSocketConnectCallBack
&& FD_ISSET (fd
, &ofds
[1])))
5021 QuitEventLoop (GetCurrentEventLoop ());
5023 #endif /* SELECT_USE_CFSOCKET */
5026 select_and_poll_event (nfds
, rfds
, wfds
, efds
, timeout
)
5028 SELECT_TYPE
*rfds
, *wfds
, *efds
;
5029 EMACS_TIME
*timeout
;
5031 OSStatus err
= noErr
;
5034 /* Try detect_input_pending before ReceiveNextEvent in the same
5035 BLOCK_INPUT block, in case that some input has already been read
5038 ENABLE_WAKEUP_FROM_RNE
;
5039 if (!detect_input_pending ())
5041 EMACS_TIME select_timeout
;
5042 EventTimeout timeoutval
=
5044 ? (EMACS_SECS (*timeout
) * kEventDurationSecond
5045 + EMACS_USECS (*timeout
) * kEventDurationMicrosecond
)
5046 : kEventDurationForever
);
5048 EMACS_SET_SECS_USECS (select_timeout
, 0, 0);
5049 r
= select (nfds
, rfds
, wfds
, efds
, &select_timeout
);
5050 if (timeoutval
== 0.0)
5051 err
= eventLoopTimedOutErr
;
5055 mac_prepare_for_quickdraw (NULL
);
5057 err
= ReceiveNextEvent (0, NULL
, timeoutval
,
5058 kEventLeaveInQueue
, NULL
);
5061 DISABLE_WAKEUP_FROM_RNE
;
5066 else if (err
== noErr
)
5068 /* Pretend that `select' is interrupted by a signal. */
5069 detect_input_pending ();
5078 sys_select (nfds
, rfds
, wfds
, efds
, timeout
)
5080 SELECT_TYPE
*rfds
, *wfds
, *efds
;
5081 EMACS_TIME
*timeout
;
5083 OSStatus err
= noErr
;
5085 EMACS_TIME select_timeout
;
5086 static SELECT_TYPE ofds
[3];
5088 if (inhibit_window_system
|| noninteractive
5089 || nfds
< 1 || rfds
== NULL
|| !FD_ISSET (0, rfds
))
5090 return select (nfds
, rfds
, wfds
, efds
, timeout
);
5104 EventTimeout timeoutval
=
5106 ? (EMACS_SECS (*timeout
) * kEventDurationSecond
5107 + EMACS_USECS (*timeout
) * kEventDurationMicrosecond
)
5108 : kEventDurationForever
);
5110 FD_SET (0, rfds
); /* sentinel */
5115 while (!(FD_ISSET (nfds
, rfds
) || (wfds
&& FD_ISSET (nfds
, wfds
))));
5120 return select_and_poll_event (nfds
, rfds
, wfds
, efds
, timeout
);
5122 /* Avoid initial overhead of RunLoop setup for the case that
5123 some input is already available. */
5124 EMACS_SET_SECS_USECS (select_timeout
, 0, 0);
5125 r
= select_and_poll_event (nfds
, rfds
, wfds
, efds
, &select_timeout
);
5126 if (r
!= 0 || timeoutval
== 0.0)
5133 #if SELECT_USE_CFSOCKET
5134 if (timeoutval
> 0 && timeoutval
<= SELECT_TIMEOUT_THRESHOLD_RUNLOOP
)
5135 goto poll_periodically
;
5137 /* Try detect_input_pending before ReceiveNextEvent in the same
5138 BLOCK_INPUT block, in case that some input has already been
5139 read asynchronously. */
5141 ENABLE_WAKEUP_FROM_RNE
;
5142 if (!detect_input_pending ())
5145 CFRunLoopRef runloop
=
5146 (CFRunLoopRef
) GetCFRunLoopFromEventLoop (GetCurrentEventLoop ());
5147 static const CFSocketContext context
= {0, ofds
, NULL
, NULL
, NULL
};
5148 static CFMutableDictionaryRef sources
;
5150 if (sources
== NULL
)
5152 CFDictionaryCreateMutable (NULL
, 0, NULL
,
5153 &kCFTypeDictionaryValueCallBacks
);
5155 for (minfd
= 1; ; minfd
++) /* nfds-1 works as a sentinel. */
5156 if (FD_ISSET (minfd
, rfds
) || (wfds
&& FD_ISSET (minfd
, wfds
)))
5159 for (fd
= minfd
; fd
< nfds
; fd
++)
5160 if (FD_ISSET (fd
, rfds
) || (wfds
&& FD_ISSET (fd
, wfds
)))
5162 void *key
= (void *) fd
;
5163 CFRunLoopSourceRef source
=
5164 (CFRunLoopSourceRef
) CFDictionaryGetValue (sources
, key
);
5168 CFSocketRef socket
=
5169 CFSocketCreateWithNative (NULL
, fd
,
5170 (kCFSocketReadCallBack
5171 | kCFSocketConnectCallBack
),
5172 socket_callback
, &context
);
5176 source
= CFSocketCreateRunLoopSource (NULL
, socket
, 0);
5180 CFDictionaryAddValue (sources
, key
, source
);
5183 CFRunLoopAddSource (runloop
, source
, kCFRunLoopDefaultMode
);
5187 mac_prepare_for_quickdraw (NULL
);
5189 err
= ReceiveNextEvent (0, NULL
, timeoutval
,
5190 kEventLeaveInQueue
, NULL
);
5192 for (fd
= minfd
; fd
< nfds
; fd
++)
5193 if (FD_ISSET (fd
, rfds
) || (wfds
&& FD_ISSET (fd
, wfds
)))
5195 void *key
= (void *) fd
;
5196 CFRunLoopSourceRef source
=
5197 (CFRunLoopSourceRef
) CFDictionaryGetValue (sources
, key
);
5199 CFRunLoopRemoveSource (runloop
, source
, kCFRunLoopDefaultMode
);
5202 DISABLE_WAKEUP_FROM_RNE
;
5205 if (err
== noErr
|| err
== eventLoopQuitErr
)
5207 EMACS_SET_SECS_USECS (select_timeout
, 0, 0);
5208 return select_and_poll_event (nfds
, rfds
, wfds
, efds
,
5218 #endif /* SELECT_USE_CFSOCKET */
5223 EMACS_TIME end_time
, now
, remaining_time
;
5227 remaining_time
= *timeout
;
5228 EMACS_GET_TIME (now
);
5229 EMACS_ADD_TIME (end_time
, now
, remaining_time
);
5234 EMACS_SET_SECS_USECS (select_timeout
, 0, SELECT_POLLING_PERIOD_USEC
);
5235 if (timeout
&& EMACS_TIME_LT (remaining_time
, select_timeout
))
5236 select_timeout
= remaining_time
;
5237 r
= select_and_poll_event (nfds
, rfds
, wfds
, efds
, &select_timeout
);
5249 EMACS_GET_TIME (now
);
5250 EMACS_SUB_TIME (remaining_time
, end_time
, now
);
5253 while (!timeout
|| EMACS_TIME_LT (now
, end_time
));
5255 EMACS_SET_SECS_USECS (select_timeout
, 0, 0);
5256 return select_and_poll_event (nfds
, rfds
, wfds
, efds
, &select_timeout
);
5260 /* Set up environment variables so that Emacs can correctly find its
5261 support files when packaged as an application bundle. Directories
5262 placed in /usr/local/share/emacs/<emacs-version>/, /usr/local/bin,
5263 and /usr/local/libexec/emacs/<emacs-version>/<system-configuration>
5264 by `make install' by default can instead be placed in
5265 .../Emacs.app/Contents/Resources/ and
5266 .../Emacs.app/Contents/MacOS/. Each of these environment variables
5267 is changed only if it is not already set. Presumably if the user
5268 sets an environment variable, he will want to use files in his path
5269 instead of ones in the application bundle. */
5271 init_mac_osx_environment ()
5275 CFStringRef cf_app_bundle_pathname
;
5276 int app_bundle_pathname_len
;
5277 char *app_bundle_pathname
;
5281 /* Initialize locale related variables. */
5282 mac_system_script_code
=
5283 (ScriptCode
) GetScriptManagerVariable (smSysScript
);
5284 Vmac_system_locale
= mac_get_system_locale ();
5286 /* Fetch the pathname of the application bundle as a C string into
5287 app_bundle_pathname. */
5289 bundle
= CFBundleGetMainBundle ();
5290 if (!bundle
|| CFBundleGetIdentifier (bundle
) == NULL
)
5292 /* We could not find the bundle identifier. For now, prevent
5293 the fatal error by bringing it up in the terminal. */
5294 inhibit_window_system
= 1;
5298 bundleURL
= CFBundleCopyBundleURL (bundle
);
5302 cf_app_bundle_pathname
= CFURLCopyFileSystemPath (bundleURL
,
5303 kCFURLPOSIXPathStyle
);
5304 app_bundle_pathname_len
= CFStringGetLength (cf_app_bundle_pathname
);
5305 app_bundle_pathname
= (char *) alloca (app_bundle_pathname_len
+ 1);
5307 if (!CFStringGetCString (cf_app_bundle_pathname
,
5308 app_bundle_pathname
,
5309 app_bundle_pathname_len
+ 1,
5310 kCFStringEncodingISOLatin1
))
5312 CFRelease (cf_app_bundle_pathname
);
5316 CFRelease (cf_app_bundle_pathname
);
5318 /* P should have sufficient room for the pathname of the bundle plus
5319 the subpath in it leading to the respective directories. Q
5320 should have three times that much room because EMACSLOADPATH can
5321 have the value "<path to lisp dir>:<path to leim dir>:<path to
5323 p
= (char *) alloca (app_bundle_pathname_len
+ 50);
5324 q
= (char *) alloca (3 * app_bundle_pathname_len
+ 150);
5325 if (!getenv ("EMACSLOADPATH"))
5329 strcpy (p
, app_bundle_pathname
);
5330 strcat (p
, "/Contents/Resources/lisp");
5331 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
5334 strcpy (p
, app_bundle_pathname
);
5335 strcat (p
, "/Contents/Resources/leim");
5336 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
5343 strcpy (p
, app_bundle_pathname
);
5344 strcat (p
, "/Contents/Resources/site-lisp");
5345 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
5353 setenv ("EMACSLOADPATH", q
, 1);
5356 if (!getenv ("EMACSPATH"))
5360 strcpy (p
, app_bundle_pathname
);
5361 strcat (p
, "/Contents/MacOS/libexec");
5362 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
5365 strcpy (p
, app_bundle_pathname
);
5366 strcat (p
, "/Contents/MacOS/bin");
5367 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
5375 setenv ("EMACSPATH", q
, 1);
5378 if (!getenv ("EMACSDATA"))
5380 strcpy (p
, app_bundle_pathname
);
5381 strcat (p
, "/Contents/Resources/etc");
5382 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
5383 setenv ("EMACSDATA", p
, 1);
5386 if (!getenv ("EMACSDOC"))
5388 strcpy (p
, app_bundle_pathname
);
5389 strcat (p
, "/Contents/Resources/etc");
5390 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
5391 setenv ("EMACSDOC", p
, 1);
5394 if (!getenv ("INFOPATH"))
5396 strcpy (p
, app_bundle_pathname
);
5397 strcat (p
, "/Contents/Resources/info");
5398 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
5399 setenv ("INFOPATH", p
, 1);
5402 #endif /* MAC_OSX */
5404 #if TARGET_API_MAC_CARBON
5406 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 ();
5418 Qundecoded_file_name
= intern ("undecoded-file-name");
5419 staticpro (&Qundecoded_file_name
);
5421 #if TARGET_API_MAC_CARBON
5422 Qstring
= intern ("string"); staticpro (&Qstring
);
5423 Qnumber
= intern ("number"); staticpro (&Qnumber
);
5424 Qboolean
= intern ("boolean"); staticpro (&Qboolean
);
5425 Qdate
= intern ("date"); staticpro (&Qdate
);
5426 Qdata
= intern ("data"); staticpro (&Qdata
);
5427 Qarray
= intern ("array"); staticpro (&Qarray
);
5428 Qdictionary
= intern ("dictionary"); staticpro (&Qdictionary
);
5430 Qxml
= intern ("xml");
5433 Qmime_charset
= intern ("mime-charset");
5434 staticpro (&Qmime_charset
);
5436 QNFD
= intern ("NFD"); staticpro (&QNFD
);
5437 QNFKD
= intern ("NFKD"); staticpro (&QNFKD
);
5438 QNFC
= intern ("NFC"); staticpro (&QNFC
);
5439 QNFKC
= intern ("NFKC"); staticpro (&QNFKC
);
5440 QHFS_plus_D
= intern ("HFS+D"); staticpro (&QHFS_plus_D
);
5441 QHFS_plus_C
= intern ("HFS+C"); staticpro (&QHFS_plus_C
);
5447 for (i
= 0; i
< sizeof (ae_attr_table
) / sizeof (ae_attr_table
[0]); i
++)
5449 ae_attr_table
[i
].symbol
= intern (ae_attr_table
[i
].name
);
5450 staticpro (&ae_attr_table
[i
].symbol
);
5454 defsubr (&Smac_coerce_ae_data
);
5455 #if TARGET_API_MAC_CARBON
5456 defsubr (&Smac_get_preference
);
5457 defsubr (&Smac_code_convert_string
);
5458 defsubr (&Smac_process_hi_command
);
5461 defsubr (&Smac_set_file_creator
);
5462 defsubr (&Smac_set_file_type
);
5463 defsubr (&Smac_get_file_creator
);
5464 defsubr (&Smac_get_file_type
);
5465 defsubr (&Sdo_applescript
);
5466 defsubr (&Smac_file_name_to_posix
);
5467 defsubr (&Sposix_file_name_to_mac
);
5469 DEFVAR_INT ("mac-system-script-code", &mac_system_script_code
,
5470 doc
: /* The system script code. */);
5471 mac_system_script_code
= (ScriptCode
) GetScriptManagerVariable (smSysScript
);
5473 DEFVAR_LISP ("mac-system-locale", &Vmac_system_locale
,
5474 doc
: /* The system locale identifier string.
5475 This is not a POSIX locale ID, but an ICU locale ID. So encoding
5476 information is not included. */);
5477 Vmac_system_locale
= mac_get_system_locale ();
5480 /* arch-tag: 29d30c1f-0c6b-4f88-8a6d-0558d7f9dbff
5481 (do not change this comment) */