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
);
1831 app_id
= kCFPreferencesCurrentApplication
;
1834 app_id
= cfstring_create_with_utf8_cstring (application
);
1838 if (!CFPreferencesAppSynchronize (app_id
))
1841 key_set
= CFSetCreateMutable (NULL
, 0, &kCFCopyStringSetCallBacks
);
1842 if (key_set
== NULL
)
1844 for (iu
= 0; iu
< sizeof (user_doms
) / sizeof (*user_doms
) ; iu
++)
1845 for (ih
= 0; ih
< sizeof (host_doms
) / sizeof (*host_doms
); ih
++)
1847 key_array
= CFPreferencesCopyKeyList (app_id
, user_doms
[iu
],
1851 count
= CFArrayGetCount (key_array
);
1852 for (index
= 0; index
< count
; index
++)
1853 CFSetAddValue (key_set
,
1854 CFArrayGetValueAtIndex (key_array
, index
));
1855 CFRelease (key_array
);
1859 count
= CFSetGetCount (key_set
);
1860 keys
= xmalloc (sizeof (CFStringRef
) * count
);
1861 CFSetGetValues (key_set
, (const void **)keys
);
1862 for (index
= 0; index
< count
; index
++)
1864 res_name
= SDATA (cfstring_to_lisp_nodecode (keys
[index
]));
1865 quarks
= parse_resource_name (&res_name
);
1866 if (!(NILP (quarks
) || *res_name
))
1868 plist
= CFPreferencesCopyAppValue (keys
[index
], app_id
);
1869 value
= xrm_cfproperty_list_to_value (plist
);
1872 xrm_q_put_resource (database
, quarks
, value
);
1879 CFRelease (key_set
);
1888 return xrm_create_database ();
1895 /* The following functions with "sys_" prefix are stubs to Unix
1896 functions that have already been implemented by CW or MPW. The
1897 calls to them in Emacs source course are #define'd to call the sys_
1898 versions by the header files s-mac.h. In these stubs pathnames are
1899 converted between their Unix and Mac forms. */
1902 /* Unix epoch is Jan 1, 1970 while Mac epoch is Jan 1, 1904: 66 years
1903 + 17 leap days. These are for adjusting time values returned by
1904 MacOS Toolbox functions. */
1906 #define MAC_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
1909 #if __MSL__ < 0x6000
1910 /* CW Pro 5 epoch is Jan 1, 1900 (aaarghhhhh!); remember, 1900 is not
1911 a leap year! This is for adjusting time_t values returned by MSL
1913 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 70 + 17) * 24 * 60 * 60)
1914 #else /* __MSL__ >= 0x6000 */
1915 /* CW changes Pro 6 to follow Unix! */
1916 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
1917 #endif /* __MSL__ >= 0x6000 */
1919 /* MPW library functions follow Unix (confused?). */
1920 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
1921 #else /* not __MRC__ */
1923 #endif /* not __MRC__ */
1926 /* Define our own stat function for both MrC and CW. The reason for
1927 doing this: "stat" is both the name of a struct and function name:
1928 can't use the same trick like that for sys_open, sys_close, etc. to
1929 redirect Emacs's calls to our own version that converts Unix style
1930 filenames to Mac style filename because all sorts of compilation
1931 errors will be generated if stat is #define'd to be sys_stat. */
1934 stat_noalias (const char *path
, struct stat
*buf
)
1936 char mac_pathname
[MAXPATHLEN
+1];
1939 if (posix_to_mac_pathname (path
, mac_pathname
, MAXPATHLEN
+1) == 0)
1942 c2pstr (mac_pathname
);
1943 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
1944 cipb
.hFileInfo
.ioVRefNum
= 0;
1945 cipb
.hFileInfo
.ioDirID
= 0;
1946 cipb
.hFileInfo
.ioFDirIndex
= 0;
1947 /* set to 0 to get information about specific dir or file */
1949 errno
= PBGetCatInfo (&cipb
, false);
1950 if (errno
== -43) /* -43: fnfErr defined in Errors.h */
1955 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* bit 4 = 1 for directories */
1957 buf
->st_mode
= S_IFDIR
| S_IREAD
| S_IEXEC
;
1959 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x1))
1960 buf
->st_mode
|= S_IWRITE
; /* bit 1 = 1 for locked files/directories */
1961 buf
->st_ino
= cipb
.dirInfo
.ioDrDirID
;
1962 buf
->st_dev
= cipb
.dirInfo
.ioVRefNum
;
1963 buf
->st_size
= cipb
.dirInfo
.ioDrNmFls
;
1964 /* size of dir = number of files and dirs */
1967 = cipb
.dirInfo
.ioDrMdDat
- MAC_UNIX_EPOCH_DIFF
;
1968 buf
->st_ctime
= cipb
.dirInfo
.ioDrCrDat
- MAC_UNIX_EPOCH_DIFF
;
1972 buf
->st_mode
= S_IFREG
| S_IREAD
;
1973 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x1))
1974 buf
->st_mode
|= S_IWRITE
; /* bit 1 = 1 for locked files/directories */
1975 if (cipb
.hFileInfo
.ioFlFndrInfo
.fdType
== 'APPL')
1976 buf
->st_mode
|= S_IEXEC
;
1977 buf
->st_ino
= cipb
.hFileInfo
.ioDirID
;
1978 buf
->st_dev
= cipb
.hFileInfo
.ioVRefNum
;
1979 buf
->st_size
= cipb
.hFileInfo
.ioFlLgLen
;
1982 = cipb
.hFileInfo
.ioFlMdDat
- MAC_UNIX_EPOCH_DIFF
;
1983 buf
->st_ctime
= cipb
.hFileInfo
.ioFlCrDat
- MAC_UNIX_EPOCH_DIFF
;
1986 if (cipb
.hFileInfo
.ioFlFndrInfo
.fdFlags
& 0x8000)
1988 /* identify alias files as symlinks */
1989 buf
->st_mode
&= ~S_IFREG
;
1990 buf
->st_mode
|= S_IFLNK
;
1994 buf
->st_uid
= getuid ();
1995 buf
->st_gid
= getgid ();
2003 lstat (const char *path
, struct stat
*buf
)
2006 char true_pathname
[MAXPATHLEN
+1];
2008 /* Try looking for the file without resolving aliases first. */
2009 if ((result
= stat_noalias (path
, buf
)) >= 0)
2012 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
2015 return stat_noalias (true_pathname
, buf
);
2020 stat (const char *path
, struct stat
*sb
)
2023 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
2026 if ((result
= stat_noalias (path
, sb
)) >= 0 &&
2027 ! (sb
->st_mode
& S_IFLNK
))
2030 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
2033 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
2036 fully_resolved_name
[len
] = '\0';
2037 /* in fact our readlink terminates strings */
2038 return lstat (fully_resolved_name
, sb
);
2041 return lstat (true_pathname
, sb
);
2046 /* CW defines fstat in stat.mac.c while MPW does not provide this
2047 function. Without the information of how to get from a file
2048 descriptor in MPW StdCLib to a Mac OS file spec, it should be hard
2049 to implement this function. Fortunately, there is only one place
2050 where this function is called in our configuration: in fileio.c,
2051 where only the st_dev and st_ino fields are used to determine
2052 whether two fildes point to different i-nodes to prevent copying
2053 a file onto itself equal. What we have here probably needs
2057 fstat (int fildes
, struct stat
*buf
)
2060 buf
->st_ino
= fildes
;
2061 buf
->st_mode
= S_IFREG
; /* added by T.I. for the copy-file */
2062 return 0; /* success */
2064 #endif /* __MRC__ */
2068 mkdir (const char *dirname
, int mode
)
2070 #pragma unused(mode)
2073 char true_pathname
[MAXPATHLEN
+1], mac_pathname
[MAXPATHLEN
+1];
2075 if (find_true_pathname (dirname
, true_pathname
, MAXPATHLEN
+1) == -1)
2078 if (posix_to_mac_pathname (true_pathname
, mac_pathname
, MAXPATHLEN
+1) == 0)
2081 c2pstr (mac_pathname
);
2082 hfpb
.ioNamePtr
= mac_pathname
;
2083 hfpb
.ioVRefNum
= 0; /* ignored unless name is invalid */
2084 hfpb
.ioDirID
= 0; /* parent is the root */
2086 errno
= PBDirCreate ((HParmBlkPtr
) &hfpb
, false);
2087 /* just return the Mac OSErr code for now */
2088 return errno
== noErr
? 0 : -1;
2093 sys_rmdir (const char *dirname
)
2096 char mac_pathname
[MAXPATHLEN
+1];
2098 if (posix_to_mac_pathname (dirname
, mac_pathname
, MAXPATHLEN
+1) == 0)
2101 c2pstr (mac_pathname
);
2102 hfpb
.ioNamePtr
= mac_pathname
;
2103 hfpb
.ioVRefNum
= 0; /* ignored unless name is invalid */
2104 hfpb
.ioDirID
= 0; /* parent is the root */
2106 errno
= PBHDelete ((HParmBlkPtr
) &hfpb
, false);
2107 return errno
== noErr
? 0 : -1;
2112 /* No implementation yet. */
2114 execvp (const char *path
, ...)
2118 #endif /* __MRC__ */
2122 utime (const char *path
, const struct utimbuf
*times
)
2124 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
2126 char mac_pathname
[MAXPATHLEN
+1];
2129 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
2132 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
2134 fully_resolved_name
[len
] = '\0';
2136 strcpy (fully_resolved_name
, true_pathname
);
2138 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
2141 c2pstr (mac_pathname
);
2142 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
2143 cipb
.hFileInfo
.ioVRefNum
= 0;
2144 cipb
.hFileInfo
.ioDirID
= 0;
2145 cipb
.hFileInfo
.ioFDirIndex
= 0;
2146 /* set to 0 to get information about specific dir or file */
2148 errno
= PBGetCatInfo (&cipb
, false);
2152 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* bit 4 = 1 for directories */
2155 cipb
.dirInfo
.ioDrMdDat
= times
->modtime
+ MAC_UNIX_EPOCH_DIFF
;
2157 GetDateTime (&cipb
.dirInfo
.ioDrMdDat
);
2162 cipb
.hFileInfo
.ioFlMdDat
= times
->modtime
+ MAC_UNIX_EPOCH_DIFF
;
2164 GetDateTime (&cipb
.hFileInfo
.ioFlMdDat
);
2167 errno
= PBSetCatInfo (&cipb
, false);
2168 return errno
== noErr
? 0 : -1;
2182 /* Like stat, but test for access mode in hfpb.ioFlAttrib */
2184 access (const char *path
, int mode
)
2186 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
2188 char mac_pathname
[MAXPATHLEN
+1];
2191 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
2194 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
2196 fully_resolved_name
[len
] = '\0';
2198 strcpy (fully_resolved_name
, true_pathname
);
2200 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
2203 c2pstr (mac_pathname
);
2204 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
2205 cipb
.hFileInfo
.ioVRefNum
= 0;
2206 cipb
.hFileInfo
.ioDirID
= 0;
2207 cipb
.hFileInfo
.ioFDirIndex
= 0;
2208 /* set to 0 to get information about specific dir or file */
2210 errno
= PBGetCatInfo (&cipb
, false);
2214 if (mode
== F_OK
) /* got this far, file exists */
2218 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* path refers to a directory */
2222 if (cipb
.hFileInfo
.ioFlFndrInfo
.fdType
== 'APPL')
2229 return (cipb
.hFileInfo
.ioFlAttrib
& 0x1) ? -1 : 0;
2230 /* don't allow if lock bit is on */
2236 #define DEV_NULL_FD 0x10000
2240 sys_open (const char *path
, int oflag
)
2242 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
2244 char mac_pathname
[MAXPATHLEN
+1];
2246 if (strcmp (path
, "/dev/null") == 0)
2247 return DEV_NULL_FD
; /* some bogus fd to be ignored in write */
2249 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
2252 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
2254 fully_resolved_name
[len
] = '\0';
2256 strcpy (fully_resolved_name
, true_pathname
);
2258 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
2263 int res
= open (mac_pathname
, oflag
);
2264 /* if (oflag == O_WRONLY || oflag == O_RDWR) */
2265 if (oflag
& O_CREAT
)
2266 fsetfileinfo (mac_pathname
, MAC_EMACS_CREATOR_CODE
, 'TEXT');
2268 #else /* not __MRC__ */
2269 return open (mac_pathname
, oflag
);
2270 #endif /* not __MRC__ */
2277 sys_creat (const char *path
, mode_t mode
)
2279 char true_pathname
[MAXPATHLEN
+1];
2281 char mac_pathname
[MAXPATHLEN
+1];
2283 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
2286 if (!posix_to_mac_pathname (true_pathname
, mac_pathname
, MAXPATHLEN
+1))
2291 int result
= creat (mac_pathname
);
2292 fsetfileinfo (mac_pathname
, MAC_EMACS_CREATOR_CODE
, 'TEXT');
2294 #else /* not __MRC__ */
2295 return creat (mac_pathname
, mode
);
2296 #endif /* not __MRC__ */
2303 sys_unlink (const char *path
)
2305 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
2307 char mac_pathname
[MAXPATHLEN
+1];
2309 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
2312 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
2314 fully_resolved_name
[len
] = '\0';
2316 strcpy (fully_resolved_name
, true_pathname
);
2318 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
2321 return unlink (mac_pathname
);
2327 sys_read (int fildes
, char *buf
, int count
)
2329 if (fildes
== 0) /* this should not be used for console input */
2332 #if __MSL__ >= 0x6000
2333 return _read (fildes
, buf
, count
);
2335 return read (fildes
, buf
, count
);
2342 sys_write (int fildes
, const char *buf
, int count
)
2344 if (fildes
== DEV_NULL_FD
)
2347 #if __MSL__ >= 0x6000
2348 return _write (fildes
, buf
, count
);
2350 return write (fildes
, buf
, count
);
2357 sys_rename (const char * old_name
, const char * new_name
)
2359 char true_old_pathname
[MAXPATHLEN
+1], true_new_pathname
[MAXPATHLEN
+1];
2360 char fully_resolved_old_name
[MAXPATHLEN
+1];
2362 char mac_old_name
[MAXPATHLEN
+1], mac_new_name
[MAXPATHLEN
+1];
2364 if (find_true_pathname (old_name
, true_old_pathname
, MAXPATHLEN
+1) == -1)
2367 len
= readlink (true_old_pathname
, fully_resolved_old_name
, MAXPATHLEN
);
2369 fully_resolved_old_name
[len
] = '\0';
2371 strcpy (fully_resolved_old_name
, true_old_pathname
);
2373 if (find_true_pathname (new_name
, true_new_pathname
, MAXPATHLEN
+1) == -1)
2376 if (strcmp (fully_resolved_old_name
, true_new_pathname
) == 0)
2379 if (!posix_to_mac_pathname (fully_resolved_old_name
,
2384 if (!posix_to_mac_pathname(true_new_pathname
, mac_new_name
, MAXPATHLEN
+1))
2387 /* If a file with new_name already exists, rename deletes the old
2388 file in Unix. CW version fails in these situation. So we add a
2389 call to unlink here. */
2390 (void) unlink (mac_new_name
);
2392 return rename (mac_old_name
, mac_new_name
);
2397 extern FILE *fopen (const char *name
, const char *mode
);
2399 sys_fopen (const char *name
, const char *mode
)
2401 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
2403 char mac_pathname
[MAXPATHLEN
+1];
2405 if (find_true_pathname (name
, true_pathname
, MAXPATHLEN
+1) == -1)
2408 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
2410 fully_resolved_name
[len
] = '\0';
2412 strcpy (fully_resolved_name
, true_pathname
);
2414 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
2419 if (mode
[0] == 'w' || mode
[0] == 'a')
2420 fsetfileinfo (mac_pathname
, MAC_EMACS_CREATOR_CODE
, 'TEXT');
2421 #endif /* not __MRC__ */
2422 return fopen (mac_pathname
, mode
);
2427 extern Boolean mac_wait_next_event
P_ ((EventRecord
*, UInt32
, Boolean
));
2430 select (nfds
, rfds
, wfds
, efds
, timeout
)
2432 SELECT_TYPE
*rfds
, *wfds
, *efds
;
2433 EMACS_TIME
*timeout
;
2435 OSStatus err
= noErr
;
2437 /* Can only handle wait for keyboard input. */
2438 if (nfds
> 1 || wfds
|| efds
)
2441 /* Try detect_input_pending before ReceiveNextEvent in the same
2442 BLOCK_INPUT block, in case that some input has already been read
2445 ENABLE_WAKEUP_FROM_RNE
;
2446 if (!detect_input_pending ())
2448 #if TARGET_API_MAC_CARBON
2449 EventTimeout timeoutval
=
2451 ? (EMACS_SECS (*timeout
) * kEventDurationSecond
2452 + EMACS_USECS (*timeout
) * kEventDurationMicrosecond
)
2453 : kEventDurationForever
);
2455 if (timeoutval
== 0.0)
2456 err
= eventLoopTimedOutErr
;
2458 err
= ReceiveNextEvent (0, NULL
, timeoutval
,
2459 kEventLeaveInQueue
, NULL
);
2460 #else /* not TARGET_API_MAC_CARBON */
2462 UInt32 sleep_time
= EMACS_SECS (*timeout
) * 60 +
2463 ((EMACS_USECS (*timeout
) * 60) / 1000000);
2465 if (sleep_time
== 0)
2466 err
= -9875; /* eventLoopTimedOutErr */
2469 if (mac_wait_next_event (&e
, sleep_time
, false))
2472 err
= -9875; /* eventLoopTimedOutErr */
2474 #endif /* not TARGET_API_MAC_CARBON */
2476 DISABLE_WAKEUP_FROM_RNE
;
2481 /* Pretend that `select' is interrupted by a signal. */
2482 detect_input_pending ();
2495 /* Simulation of SIGALRM. The stub for function signal stores the
2496 signal handler function in alarm_signal_func if a SIGALRM is
2500 #include "syssignal.h"
2502 static TMTask mac_atimer_task
;
2504 static QElemPtr mac_atimer_qlink
= (QElemPtr
) &mac_atimer_task
;
2506 static int signal_mask
= 0;
2509 __sigfun alarm_signal_func
= (__sigfun
) 0;
2511 __signal_func_ptr alarm_signal_func
= (__signal_func_ptr
) 0;
2512 #else /* not __MRC__ and not __MWERKS__ */
2514 #endif /* not __MRC__ and not __MWERKS__ */
2518 extern __sigfun
signal (int signal
, __sigfun signal_func
);
2520 sys_signal (int signal_num
, __sigfun signal_func
)
2522 extern __signal_func_ptr
signal (int signal
, __signal_func_ptr signal_func
);
2524 sys_signal (int signal_num
, __signal_func_ptr signal_func
)
2525 #else /* not __MRC__ and not __MWERKS__ */
2527 #endif /* not __MRC__ and not __MWERKS__ */
2529 if (signal_num
!= SIGALRM
)
2530 return signal (signal_num
, signal_func
);
2534 __sigfun old_signal_func
;
2536 __signal_func_ptr old_signal_func
;
2540 old_signal_func
= alarm_signal_func
;
2541 alarm_signal_func
= signal_func
;
2542 return old_signal_func
;
2548 mac_atimer_handler (qlink
)
2551 if (alarm_signal_func
)
2552 (alarm_signal_func
) (SIGALRM
);
2557 set_mac_atimer (count
)
2560 static TimerUPP mac_atimer_handlerUPP
= NULL
;
2562 if (mac_atimer_handlerUPP
== NULL
)
2563 mac_atimer_handlerUPP
= NewTimerUPP (mac_atimer_handler
);
2564 mac_atimer_task
.tmCount
= 0;
2565 mac_atimer_task
.tmAddr
= mac_atimer_handlerUPP
;
2566 mac_atimer_qlink
= (QElemPtr
) &mac_atimer_task
;
2567 InsTime (mac_atimer_qlink
);
2569 PrimeTime (mac_atimer_qlink
, count
);
2574 remove_mac_atimer (remaining_count
)
2575 long *remaining_count
;
2577 if (mac_atimer_qlink
)
2579 RmvTime (mac_atimer_qlink
);
2580 if (remaining_count
)
2581 *remaining_count
= mac_atimer_task
.tmCount
;
2582 mac_atimer_qlink
= NULL
;
2594 int old_mask
= signal_mask
;
2596 signal_mask
|= mask
;
2598 if ((old_mask
^ signal_mask
) & sigmask (SIGALRM
))
2599 remove_mac_atimer (NULL
);
2606 sigsetmask (int mask
)
2608 int old_mask
= signal_mask
;
2612 if ((old_mask
^ signal_mask
) & sigmask (SIGALRM
))
2613 if (signal_mask
& sigmask (SIGALRM
))
2614 remove_mac_atimer (NULL
);
2616 set_mac_atimer (mac_atimer_task
.tmCount
);
2625 long remaining_count
;
2627 if (remove_mac_atimer (&remaining_count
) == 0)
2629 set_mac_atimer (seconds
* 1000);
2631 return remaining_count
/ 1000;
2635 mac_atimer_task
.tmCount
= seconds
* 1000;
2643 setitimer (which
, value
, ovalue
)
2645 const struct itimerval
*value
;
2646 struct itimerval
*ovalue
;
2648 long remaining_count
;
2649 long count
= (EMACS_SECS (value
->it_value
) * 1000
2650 + (EMACS_USECS (value
->it_value
) + 999) / 1000);
2652 if (remove_mac_atimer (&remaining_count
) == 0)
2656 bzero (ovalue
, sizeof (*ovalue
));
2657 EMACS_SET_SECS_USECS (ovalue
->it_value
, remaining_count
/ 1000,
2658 (remaining_count
% 1000) * 1000);
2660 set_mac_atimer (count
);
2663 mac_atimer_task
.tmCount
= count
;
2669 /* gettimeofday should return the amount of time (in a timeval
2670 structure) since midnight today. The toolbox function Microseconds
2671 returns the number of microseconds (in a UnsignedWide value) since
2672 the machine was booted. Also making this complicated is WideAdd,
2673 WideSubtract, etc. take wide values. */
2680 static wide wall_clock_at_epoch
, clicks_at_epoch
;
2681 UnsignedWide uw_microseconds
;
2682 wide w_microseconds
;
2683 time_t sys_time (time_t *);
2685 /* If this function is called for the first time, record the number
2686 of seconds since midnight and the number of microseconds since
2687 boot at the time of this first call. */
2692 systime
= sys_time (NULL
);
2693 /* Store microseconds since midnight in wall_clock_at_epoch. */
2694 WideMultiply (systime
, 1000000L, &wall_clock_at_epoch
);
2695 Microseconds (&uw_microseconds
);
2696 /* Store microseconds since boot in clicks_at_epoch. */
2697 clicks_at_epoch
.hi
= uw_microseconds
.hi
;
2698 clicks_at_epoch
.lo
= uw_microseconds
.lo
;
2701 /* Get time since boot */
2702 Microseconds (&uw_microseconds
);
2704 /* Convert to time since midnight*/
2705 w_microseconds
.hi
= uw_microseconds
.hi
;
2706 w_microseconds
.lo
= uw_microseconds
.lo
;
2707 WideSubtract (&w_microseconds
, &clicks_at_epoch
);
2708 WideAdd (&w_microseconds
, &wall_clock_at_epoch
);
2709 tp
->tv_sec
= WideDivide (&w_microseconds
, 1000000L, &tp
->tv_usec
);
2717 sleep (unsigned int seconds
)
2719 unsigned long time_up
;
2722 time_up
= TickCount () + seconds
* 60;
2723 while (TickCount () < time_up
)
2725 /* Accept no event; just wait. by T.I. */
2726 WaitNextEvent (0, &e
, 30, NULL
);
2731 #endif /* __MRC__ */
2734 /* The time functions adjust time values according to the difference
2735 between the Unix and CW epoches. */
2738 extern struct tm
*gmtime (const time_t *);
2740 sys_gmtime (const time_t *timer
)
2742 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
2744 return gmtime (&unix_time
);
2749 extern struct tm
*localtime (const time_t *);
2751 sys_localtime (const time_t *timer
)
2753 #if __MSL__ >= 0x6000
2754 time_t unix_time
= *timer
;
2756 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
2759 return localtime (&unix_time
);
2764 extern char *ctime (const time_t *);
2766 sys_ctime (const time_t *timer
)
2768 #if __MSL__ >= 0x6000
2769 time_t unix_time
= *timer
;
2771 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
2774 return ctime (&unix_time
);
2779 extern time_t time (time_t *);
2781 sys_time (time_t *timer
)
2783 #if __MSL__ >= 0x6000
2784 time_t mac_time
= time (NULL
);
2786 time_t mac_time
= time (NULL
) - CW_OR_MPW_UNIX_EPOCH_DIFF
;
2796 /* no subprocesses, empty wait */
2806 croak (char *badfunc
)
2808 printf ("%s not yet implemented\r\n", badfunc
);
2814 mktemp (char *template)
2819 len
= strlen (template);
2821 while (k
>= 0 && template[k
] == 'X')
2824 k
++; /* make k index of first 'X' */
2828 /* Zero filled, number of digits equal to the number of X's. */
2829 sprintf (&template[k
], "%0*d", len
-k
, seqnum
++);
2838 /* Emulate getpwuid, getpwnam and others. */
2840 #define PASSWD_FIELD_SIZE 256
2842 static char my_passwd_name
[PASSWD_FIELD_SIZE
];
2843 static char my_passwd_dir
[MAXPATHLEN
+1];
2845 static struct passwd my_passwd
=
2851 static struct group my_group
=
2853 /* There are no groups on the mac, so we just return "root" as the
2859 /* Initialized by main () in macterm.c to pathname of emacs directory. */
2861 char emacs_passwd_dir
[MAXPATHLEN
+1];
2867 init_emacs_passwd_dir ()
2871 if (getwd (emacs_passwd_dir
) && getwd (my_passwd_dir
))
2873 /* Need pathname of first ancestor that begins with "emacs"
2874 since Mac emacs application is somewhere in the emacs-*
2876 int len
= strlen (emacs_passwd_dir
);
2878 /* j points to the "/" following the directory name being
2881 while (i
>= 0 && !found
)
2883 while (i
>= 0 && emacs_passwd_dir
[i
] != '/')
2885 if (emacs_passwd_dir
[i
] == '/' && i
+5 < len
)
2886 found
= (strncmp (&(emacs_passwd_dir
[i
+1]), "emacs", 5) == 0);
2888 emacs_passwd_dir
[j
+1] = '\0';
2899 /* Setting to "/" probably won't work but set it to something
2901 strcpy (emacs_passwd_dir
, "/");
2902 strcpy (my_passwd_dir
, "/");
2907 static struct passwd emacs_passwd
=
2913 static int my_passwd_inited
= 0;
2921 /* Note: my_passwd_dir initialized in int_emacs_passwd_dir to
2922 directory where Emacs was started. */
2924 owner_name
= (char **) GetResource ('STR ',-16096);
2928 BlockMove ((unsigned char *) *owner_name
,
2929 (unsigned char *) my_passwd_name
,
2931 HUnlock (owner_name
);
2932 p2cstr ((unsigned char *) my_passwd_name
);
2935 my_passwd_name
[0] = 0;
2940 getpwuid (uid_t uid
)
2942 if (!my_passwd_inited
)
2945 my_passwd_inited
= 1;
2953 getgrgid (gid_t gid
)
2960 getpwnam (const char *name
)
2962 if (strcmp (name
, "emacs") == 0)
2963 return &emacs_passwd
;
2965 if (!my_passwd_inited
)
2968 my_passwd_inited
= 1;
2975 /* The functions fork, kill, sigsetmask, sigblock, request_sigio,
2976 setpgrp, setpriority, and unrequest_sigio are defined to be empty
2997 error ("Can't spawn subshell");
3002 request_sigio (void)
3008 unrequest_sigio (void)
3023 pipe (int _fildes
[2])
3030 /* Hard and symbolic links. */
3033 symlink (const char *name1
, const char *name2
)
3041 link (const char *name1
, const char *name2
)
3047 #endif /* ! MAC_OSX */
3049 /* Determine the path name of the file specified by VREFNUM, DIRID,
3050 and NAME and place that in the buffer PATH of length
3053 path_from_vol_dir_name (char *path
, int man_path_len
, short vol_ref_num
,
3054 long dir_id
, ConstStr255Param name
)
3060 if (strlen (name
) > man_path_len
)
3063 memcpy (dir_name
, name
, name
[0]+1);
3064 memcpy (path
, name
, name
[0]+1);
3067 cipb
.dirInfo
.ioDrParID
= dir_id
;
3068 cipb
.dirInfo
.ioNamePtr
= dir_name
;
3072 cipb
.dirInfo
.ioVRefNum
= vol_ref_num
;
3073 cipb
.dirInfo
.ioFDirIndex
= -1;
3074 cipb
.dirInfo
.ioDrDirID
= cipb
.dirInfo
.ioDrParID
;
3075 /* go up to parent each time */
3077 err
= PBGetCatInfo (&cipb
, false);
3082 if (strlen (dir_name
) + strlen (path
) + 1 >= man_path_len
)
3085 strcat (dir_name
, ":");
3086 strcat (dir_name
, path
);
3087 /* attach to front since we're going up directory tree */
3088 strcpy (path
, dir_name
);
3090 while (cipb
.dirInfo
.ioDrDirID
!= fsRtDirID
);
3091 /* stop when we see the volume's root directory */
3093 return 1; /* success */
3100 posix_pathname_to_fsspec (ufn
, fs
)
3104 Str255 mac_pathname
;
3106 if (posix_to_mac_pathname (ufn
, mac_pathname
, sizeof (mac_pathname
)) == 0)
3110 c2pstr (mac_pathname
);
3111 return FSMakeFSSpec (0, 0, mac_pathname
, fs
);
3116 fsspec_to_posix_pathname (fs
, ufn
, ufnbuflen
)
3121 char mac_pathname
[MAXPATHLEN
];
3123 if (path_from_vol_dir_name (mac_pathname
, sizeof (mac_pathname
) - 1,
3124 fs
->vRefNum
, fs
->parID
, fs
->name
)
3125 && mac_to_posix_pathname (mac_pathname
, ufn
, ufnbuflen
))
3132 readlink (const char *path
, char *buf
, int bufsiz
)
3134 char mac_sym_link_name
[MAXPATHLEN
+1];
3137 Boolean target_is_folder
, was_aliased
;
3138 Str255 directory_name
, mac_pathname
;
3141 if (posix_to_mac_pathname (path
, mac_sym_link_name
, MAXPATHLEN
+1) == 0)
3144 c2pstr (mac_sym_link_name
);
3145 err
= FSMakeFSSpec (0, 0, mac_sym_link_name
, &fsspec
);
3152 err
= ResolveAliasFile (&fsspec
, true, &target_is_folder
, &was_aliased
);
3153 if (err
!= noErr
|| !was_aliased
)
3159 if (path_from_vol_dir_name (mac_pathname
, 255, fsspec
.vRefNum
, fsspec
.parID
,
3166 if (mac_to_posix_pathname (mac_pathname
, buf
, bufsiz
) == 0)
3172 return strlen (buf
);
3176 /* Convert a path to one with aliases fully expanded. */
3179 find_true_pathname (const char *path
, char *buf
, int bufsiz
)
3181 char *q
, temp
[MAXPATHLEN
+1];
3185 if (bufsiz
<= 0 || path
== 0 || path
[0] == '\0')
3192 q
= strchr (p
+ 1, '/');
3194 q
= strchr (p
, '/');
3195 len
= 0; /* loop may not be entered, e.g., for "/" */
3200 strncat (temp
, p
, q
- p
);
3201 len
= readlink (temp
, buf
, bufsiz
);
3204 if (strlen (temp
) + 1 > bufsiz
)
3214 if (len
+ strlen (p
) + 1 >= bufsiz
)
3218 return len
+ strlen (p
);
3223 umask (mode_t numask
)
3225 static mode_t mask
= 022;
3226 mode_t oldmask
= mask
;
3233 chmod (const char *path
, mode_t mode
)
3235 /* say it always succeed for now */
3241 fchmod (int fd
, mode_t mode
)
3243 /* say it always succeed for now */
3249 fchown (int fd
, uid_t owner
, gid_t group
)
3251 /* say it always succeed for now */
3260 return fcntl (oldd
, F_DUPFD
, 0);
3262 /* current implementation of fcntl in fcntl.mac.c simply returns old
3264 return fcntl (oldd
, F_DUPFD
);
3271 /* This is from the original sysdep.c. Emulate BSD dup2. First close
3272 newd if it already exists. Then, attempt to dup oldd. If not
3273 successful, call dup2 recursively until we are, then close the
3274 unsuccessful ones. */
3277 dup2 (int oldd
, int newd
)
3288 ret
= dup2 (oldd
, newd
);
3294 /* let it fail for now */
3311 ioctl (int d
, int request
, void *argp
)
3321 if (fildes
>=0 && fildes
<= 2)
3354 #endif /* __MRC__ */
3358 #if __MSL__ < 0x6000
3366 #endif /* __MWERKS__ */
3368 #endif /* ! MAC_OSX */
3371 /* Return the path to the directory in which Emacs can create
3372 temporary files. The MacOS "temporary items" directory cannot be
3373 used because it removes the file written by a process when it
3374 exits. In that sense it's more like "/dev/null" than "/tmp" (but
3375 again not exactly). And of course Emacs needs to read back the
3376 files written by its subprocesses. So here we write the files to a
3377 directory "Emacs" in the Preferences Folder. This directory is
3378 created if it does not exist. */
3381 get_temp_dir_name ()
3383 static char *temp_dir_name
= NULL
;
3388 char unix_dir_name
[MAXPATHLEN
+1];
3391 /* Cache directory name with pointer temp_dir_name.
3392 Look for it only the first time. */
3395 err
= FindFolder (kOnSystemDisk
, kPreferencesFolderType
, kCreateFolder
,
3396 &vol_ref_num
, &dir_id
);
3400 if (!path_from_vol_dir_name (full_path
, 255, vol_ref_num
, dir_id
, "\p"))
3403 if (strlen (full_path
) + 6 <= MAXPATHLEN
)
3404 strcat (full_path
, "Emacs:");
3408 if (!mac_to_posix_pathname (full_path
, unix_dir_name
, MAXPATHLEN
+1))
3411 dir
= opendir (unix_dir_name
); /* check whether temp directory exists */
3414 else if (mkdir (unix_dir_name
, 0700) != 0) /* create it if not */
3417 temp_dir_name
= (char *) malloc (strlen (unix_dir_name
) + 1);
3418 strcpy (temp_dir_name
, unix_dir_name
);
3421 return temp_dir_name
;
3426 /* Allocate and construct an array of pointers to strings from a list
3427 of strings stored in a 'STR#' resource. The returned pointer array
3428 is stored in the style of argv and environ: if the 'STR#' resource
3429 contains numString strings, a pointer array with numString+1
3430 elements is returned in which the last entry contains a null
3431 pointer. The pointer to the pointer array is passed by pointer in
3432 parameter t. The resource ID of the 'STR#' resource is passed in
3433 parameter StringListID.
3437 get_string_list (char ***t
, short string_list_id
)
3443 h
= GetResource ('STR#', string_list_id
);
3448 num_strings
= * (short *) p
;
3450 *t
= (char **) malloc (sizeof (char *) * (num_strings
+ 1));
3451 for (i
= 0; i
< num_strings
; i
++)
3453 short length
= *p
++;
3454 (*t
)[i
] = (char *) malloc (length
+ 1);
3455 strncpy ((*t
)[i
], p
, length
);
3456 (*t
)[i
][length
] = '\0';
3459 (*t
)[num_strings
] = 0;
3464 /* Return no string in case GetResource fails. Bug fixed by
3465 Ikegami Tsutomu. Caused MPW build to crash without sym -on
3466 option (no sym -on implies -opt local). */
3467 *t
= (char **) malloc (sizeof (char *));
3474 get_path_to_system_folder ()
3480 static char system_folder_unix_name
[MAXPATHLEN
+1];
3483 err
= FindFolder (kOnSystemDisk
, kSystemFolderType
, kDontCreateFolder
,
3484 &vol_ref_num
, &dir_id
);
3488 if (!path_from_vol_dir_name (full_path
, 255, vol_ref_num
, dir_id
, "\p"))
3491 if (!mac_to_posix_pathname (full_path
, system_folder_unix_name
,
3495 return system_folder_unix_name
;
3501 #define ENVIRON_STRING_LIST_ID 128
3503 /* Get environment variable definitions from STR# resource. */
3510 get_string_list (&environ
, ENVIRON_STRING_LIST_ID
);
3516 /* Make HOME directory the one Emacs starts up in if not specified
3518 if (getenv ("HOME") == NULL
)
3520 environ
= (char **) realloc (environ
, sizeof (char *) * (i
+ 2));
3523 environ
[i
] = (char *) malloc (strlen (my_passwd_dir
) + 6);
3526 strcpy (environ
[i
], "HOME=");
3527 strcat (environ
[i
], my_passwd_dir
);
3534 /* Make HOME directory the one Emacs starts up in if not specified
3536 if (getenv ("MAIL") == NULL
)
3538 environ
= (char **) realloc (environ
, sizeof (char *) * (i
+ 2));
3541 char * path_to_system_folder
= get_path_to_system_folder ();
3542 environ
[i
] = (char *) malloc (strlen (path_to_system_folder
) + 22);
3545 strcpy (environ
[i
], "MAIL=");
3546 strcat (environ
[i
], path_to_system_folder
);
3547 strcat (environ
[i
], "Eudora Folder/In");
3555 /* Return the value of the environment variable NAME. */
3558 getenv (const char *name
)
3560 int length
= strlen(name
);
3563 for (e
= environ
; *e
!= 0; e
++)
3564 if (strncmp(*e
, name
, length
) == 0 && (*e
)[length
] == '=')
3565 return &(*e
)[length
+ 1];
3567 if (strcmp (name
, "TMPDIR") == 0)
3568 return get_temp_dir_name ();
3575 /* see Interfaces&Libraries:Interfaces:CIncludes:signal.h */
3576 char *sys_siglist
[] =
3578 "Zero is not a signal!!!",
3580 "Interactive user interrupt", /* 2 */ "?",
3581 "Floating point exception", /* 4 */ "?", "?", "?",
3582 "Illegal instruction", /* 8 */ "?", "?", "?", "?", "?", "?", "?",
3583 "Segment violation", /* 16 */ "?", "?", "?", "?", "?", "?", "?",
3584 "?", "?", "?", "?", "?", "?", "?", "?",
3588 char *sys_siglist
[] =
3590 "Zero is not a signal!!!",
3592 "Floating point exception",
3593 "Illegal instruction",
3594 "Interactive user interrupt",
3595 "Segment violation",
3598 #else /* not __MRC__ and not __MWERKS__ */
3600 #endif /* not __MRC__ and not __MWERKS__ */
3603 #include <utsname.h>
3606 uname (struct utsname
*name
)
3609 system_name
= GetString (-16413); /* IM - Resource Manager Reference */
3612 BlockMove (*system_name
, name
->nodename
, (*system_name
)[0]+1);
3613 p2cstr (name
->nodename
);
3621 /* Event class of HLE sent to subprocess. */
3622 const OSType kEmacsSubprocessSend
= 'ESND';
3624 /* Event class of HLE sent back from subprocess. */
3625 const OSType kEmacsSubprocessReply
= 'ERPY';
3629 mystrchr (char *s
, char c
)
3631 while (*s
&& *s
!= c
)
3659 mystrcpy (char *to
, char *from
)
3671 /* Start a Mac subprocess. Arguments for it is passed in argv (null
3672 terminated). The process should run with the default directory
3673 "workdir", read input from "infn", and write output and error to
3674 "outfn" and "errfn", resp. The Process Manager call
3675 LaunchApplication is used to start the subprocess. We use high
3676 level events as the mechanism to pass arguments to the subprocess
3677 and to make Emacs wait for the subprocess to terminate and pass
3678 back a result code. The bulk of the code here packs the arguments
3679 into one message to be passed together with the high level event.
3680 Emacs also sometimes starts a subprocess using a shell to perform
3681 wildcard filename expansion. Since we don't really have a shell on
3682 the Mac, this case is detected and the starting of the shell is
3683 by-passed. We really need to add code here to do filename
3684 expansion to support such functionality.
3686 We can't use this strategy in Carbon because the High Level Event
3687 APIs are not available. */
3690 run_mac_command (argv
, workdir
, infn
, outfn
, errfn
)
3691 unsigned char **argv
;
3692 const char *workdir
;
3693 const char *infn
, *outfn
, *errfn
;
3695 #if TARGET_API_MAC_CARBON
3697 #else /* not TARGET_API_MAC_CARBON */
3698 char macappname
[MAXPATHLEN
+1], macworkdir
[MAXPATHLEN
+1];
3699 char macinfn
[MAXPATHLEN
+1], macoutfn
[MAXPATHLEN
+1], macerrfn
[MAXPATHLEN
+1];
3700 int paramlen
, argc
, newargc
, j
, retries
;
3701 char **newargv
, *param
, *p
;
3704 LaunchParamBlockRec lpbr
;
3705 EventRecord send_event
, reply_event
;
3706 RgnHandle cursor_region_handle
;
3708 unsigned long ref_con
, len
;
3710 if (posix_to_mac_pathname (workdir
, macworkdir
, MAXPATHLEN
+1) == 0)
3712 if (posix_to_mac_pathname (infn
, macinfn
, MAXPATHLEN
+1) == 0)
3714 if (posix_to_mac_pathname (outfn
, macoutfn
, MAXPATHLEN
+1) == 0)
3716 if (posix_to_mac_pathname (errfn
, macerrfn
, MAXPATHLEN
+1) == 0)
3719 paramlen
= strlen (macworkdir
) + strlen (macinfn
) + strlen (macoutfn
)
3720 + strlen (macerrfn
) + 4; /* count nulls at end of strings */
3729 /* If a subprocess is invoked with a shell, we receive 3 arguments
3730 of the form: "<path to emacs bins>/sh" "-c" "<path to emacs
3731 bins>/<command> <command args>" */
3732 j
= strlen (argv
[0]);
3733 if (j
>= 3 && strcmp (argv
[0]+j
-3, "/sh") == 0
3734 && argc
== 3 && strcmp (argv
[1], "-c") == 0)
3736 char *command
, *t
, tempmacpathname
[MAXPATHLEN
+1];
3738 /* The arguments for the command in argv[2] are separated by
3739 spaces. Count them and put the count in newargc. */
3740 command
= (char *) alloca (strlen (argv
[2])+2);
3741 strcpy (command
, argv
[2]);
3742 if (command
[strlen (command
) - 1] != ' ')
3743 strcat (command
, " ");
3747 t
= mystrchr (t
, ' ');
3751 t
= mystrchr (t
+1, ' ');
3754 newargv
= (char **) alloca (sizeof (char *) * newargc
);
3757 for (j
= 0; j
< newargc
; j
++)
3759 newargv
[j
] = (char *) alloca (strlen (t
) + 1);
3760 mystrcpy (newargv
[j
], t
);
3763 paramlen
+= strlen (newargv
[j
]) + 1;
3766 if (strncmp (newargv
[0], "~emacs/", 7) == 0)
3768 if (posix_to_mac_pathname (newargv
[0], tempmacpathname
, MAXPATHLEN
+1)
3773 { /* sometimes Emacs call "sh" without a path for the command */
3775 char *t
= (char *) alloca (strlen (newargv
[0]) + 7 + 1);
3776 strcpy (t
, "~emacs/");
3777 strcat (t
, newargv
[0]);
3780 openp (Vexec_path
, build_string (newargv
[0]), Vexec_suffixes
, &path
,
3781 make_number (X_OK
));
3785 if (posix_to_mac_pathname (SDATA (path
), tempmacpathname
,
3789 strcpy (macappname
, tempmacpathname
);
3793 if (posix_to_mac_pathname (argv
[0], macappname
, MAXPATHLEN
+1) == 0)
3796 newargv
= (char **) alloca (sizeof (char *) * argc
);
3798 for (j
= 1; j
< argc
; j
++)
3800 if (strncmp (argv
[j
], "~emacs/", 7) == 0)
3802 char *t
= strchr (argv
[j
], ' ');
3805 char tempcmdname
[MAXPATHLEN
+1], tempmaccmdname
[MAXPATHLEN
+1];
3806 strncpy (tempcmdname
, argv
[j
], t
-argv
[j
]);
3807 tempcmdname
[t
-argv
[j
]] = '\0';
3808 if (posix_to_mac_pathname (tempcmdname
, tempmaccmdname
,
3811 newargv
[j
] = (char *) alloca (strlen (tempmaccmdname
)
3813 strcpy (newargv
[j
], tempmaccmdname
);
3814 strcat (newargv
[j
], t
);
3818 char tempmaccmdname
[MAXPATHLEN
+1];
3819 if (posix_to_mac_pathname (argv
[j
], tempmaccmdname
,
3822 newargv
[j
] = (char *) alloca (strlen (tempmaccmdname
)+1);
3823 strcpy (newargv
[j
], tempmaccmdname
);
3827 newargv
[j
] = argv
[j
];
3828 paramlen
+= strlen (newargv
[j
]) + 1;
3832 /* After expanding all the arguments, we now know the length of the
3833 parameter block to be sent to the subprocess as a message
3834 attached to the HLE. */
3835 param
= (char *) malloc (paramlen
+ 1);
3841 /* first byte of message contains number of arguments for command */
3842 strcpy (p
, macworkdir
);
3843 p
+= strlen (macworkdir
);
3845 /* null terminate strings sent so it's possible to use strcpy over there */
3846 strcpy (p
, macinfn
);
3847 p
+= strlen (macinfn
);
3849 strcpy (p
, macoutfn
);
3850 p
+= strlen (macoutfn
);
3852 strcpy (p
, macerrfn
);
3853 p
+= strlen (macerrfn
);
3855 for (j
= 1; j
< newargc
; j
++)
3857 strcpy (p
, newargv
[j
]);
3858 p
+= strlen (newargv
[j
]);
3862 c2pstr (macappname
);
3864 iErr
= FSMakeFSSpec (0, 0, macappname
, &spec
);
3872 lpbr
.launchBlockID
= extendedBlock
;
3873 lpbr
.launchEPBLength
= extendedBlockLen
;
3874 lpbr
.launchControlFlags
= launchContinue
+ launchNoFileFlags
;
3875 lpbr
.launchAppSpec
= &spec
;
3876 lpbr
.launchAppParameters
= NULL
;
3878 iErr
= LaunchApplication (&lpbr
); /* call the subprocess */
3885 send_event
.what
= kHighLevelEvent
;
3886 send_event
.message
= kEmacsSubprocessSend
;
3887 /* Event ID stored in "where" unused */
3890 /* OS may think current subprocess has terminated if previous one
3891 terminated recently. */
3894 iErr
= PostHighLevelEvent (&send_event
, &lpbr
.launchProcessSN
, 0, param
,
3895 paramlen
+ 1, receiverIDisPSN
);
3897 while (iErr
== sessClosedErr
&& retries
-- > 0);
3905 cursor_region_handle
= NewRgn ();
3907 /* Wait for the subprocess to finish, when it will send us a ERPY
3908 high level event. */
3910 if (WaitNextEvent (highLevelEventMask
, &reply_event
, 180,
3911 cursor_region_handle
)
3912 && reply_event
.message
== kEmacsSubprocessReply
)
3915 /* The return code is sent through the refCon */
3916 iErr
= AcceptHighLevelEvent (&targ
, &ref_con
, NULL
, &len
);
3919 DisposeHandle ((Handle
) cursor_region_handle
);
3924 DisposeHandle ((Handle
) cursor_region_handle
);
3928 #endif /* not TARGET_API_MAC_CARBON */
3933 opendir (const char *dirname
)
3935 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
3936 char mac_pathname
[MAXPATHLEN
+1], vol_name
[MAXPATHLEN
+1];
3940 int len
, vol_name_len
;
3942 if (find_true_pathname (dirname
, true_pathname
, MAXPATHLEN
+1) == -1)
3945 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
3947 fully_resolved_name
[len
] = '\0';
3949 strcpy (fully_resolved_name
, true_pathname
);
3951 dirp
= (DIR *) malloc (sizeof(DIR));
3955 /* Handle special case when dirname is "/": sets up for readir to
3956 get all mount volumes. */
3957 if (strcmp (fully_resolved_name
, "/") == 0)
3959 dirp
->getting_volumes
= 1; /* special all mounted volumes DIR struct */
3960 dirp
->current_index
= 1; /* index for first volume */
3964 /* Handle typical cases: not accessing all mounted volumes. */
3965 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
3968 /* Emacs calls opendir without the trailing '/', Mac needs trailing ':' */
3969 len
= strlen (mac_pathname
);
3970 if (mac_pathname
[len
- 1] != ':' && len
< MAXPATHLEN
)
3971 strcat (mac_pathname
, ":");
3973 /* Extract volume name */
3974 vol_name_len
= strchr (mac_pathname
, ':') - mac_pathname
;
3975 strncpy (vol_name
, mac_pathname
, vol_name_len
);
3976 vol_name
[vol_name_len
] = '\0';
3977 strcat (vol_name
, ":");
3979 c2pstr (mac_pathname
);
3980 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
3981 /* using full pathname so vRefNum and DirID ignored */
3982 cipb
.hFileInfo
.ioVRefNum
= 0;
3983 cipb
.hFileInfo
.ioDirID
= 0;
3984 cipb
.hFileInfo
.ioFDirIndex
= 0;
3985 /* set to 0 to get information about specific dir or file */
3987 errno
= PBGetCatInfo (&cipb
, false);
3994 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x10)) /* bit 4 = 1 for directories */
3995 return 0; /* not a directory */
3997 dirp
->dir_id
= cipb
.dirInfo
.ioDrDirID
; /* used later in readdir */
3998 dirp
->getting_volumes
= 0;
3999 dirp
->current_index
= 1; /* index for first file/directory */
4002 vpb
.ioNamePtr
= vol_name
;
4003 /* using full pathname so vRefNum and DirID ignored */
4005 vpb
.ioVolIndex
= -1;
4006 errno
= PBHGetVInfo ((union HParamBlockRec
*) &vpb
, false);
4013 dirp
->vol_ref_num
= vpb
.ioVRefNum
;
4030 HParamBlockRec hpblock
;
4032 static struct dirent s_dirent
;
4033 static Str255 s_name
;
4037 /* Handle the root directory containing the mounted volumes. Call
4038 PBHGetVInfo specifying an index to obtain the info for a volume.
4039 PBHGetVInfo returns an error when it receives an index beyond the
4040 last volume, at which time we should return a nil dirent struct
4042 if (dp
->getting_volumes
)
4044 hpblock
.volumeParam
.ioNamePtr
= s_name
;
4045 hpblock
.volumeParam
.ioVRefNum
= 0;
4046 hpblock
.volumeParam
.ioVolIndex
= dp
->current_index
;
4048 errno
= PBHGetVInfo (&hpblock
, false);
4056 strcat (s_name
, "/"); /* need "/" for stat to work correctly */
4058 dp
->current_index
++;
4060 s_dirent
.d_ino
= hpblock
.volumeParam
.ioVRefNum
;
4061 s_dirent
.d_name
= s_name
;
4067 cipb
.hFileInfo
.ioVRefNum
= dp
->vol_ref_num
;
4068 cipb
.hFileInfo
.ioNamePtr
= s_name
;
4069 /* location to receive filename returned */
4071 /* return only visible files */
4075 cipb
.hFileInfo
.ioDirID
= dp
->dir_id
;
4076 /* directory ID found by opendir */
4077 cipb
.hFileInfo
.ioFDirIndex
= dp
->current_index
;
4079 errno
= PBGetCatInfo (&cipb
, false);
4086 /* insist on a visible entry */
4087 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* directory? */
4088 done
= !(cipb
.dirInfo
.ioDrUsrWds
.frFlags
& fInvisible
);
4090 done
= !(cipb
.hFileInfo
.ioFlFndrInfo
.fdFlags
& fInvisible
);
4092 dp
->current_index
++;
4105 s_dirent
.d_ino
= cipb
.dirInfo
.ioDrDirID
;
4106 /* value unimportant: non-zero for valid file */
4107 s_dirent
.d_name
= s_name
;
4117 char mac_pathname
[MAXPATHLEN
+1];
4118 Str255 directory_name
;
4122 if (path_from_vol_dir_name (mac_pathname
, 255, 0, 0, "\p") == 0)
4125 if (mac_to_posix_pathname (mac_pathname
, path
, MAXPATHLEN
+1) == 0)
4131 #endif /* ! MAC_OSX */
4135 initialize_applescript ()
4140 /* if open fails, as_scripting_component is set to NULL. Its
4141 subsequent use in OSA calls will fail with badComponentInstance
4143 as_scripting_component
= OpenDefaultComponent (kOSAComponentType
,
4144 kAppleScriptSubtype
);
4146 null_desc
.descriptorType
= typeNull
;
4147 null_desc
.dataHandle
= 0;
4148 osaerror
= OSAMakeContext (as_scripting_component
, &null_desc
,
4149 kOSANullScript
, &as_script_context
);
4151 as_script_context
= kOSANullScript
;
4152 /* use default context if create fails */
4157 terminate_applescript()
4159 OSADispose (as_scripting_component
, as_script_context
);
4160 CloseComponent (as_scripting_component
);
4163 /* Convert a lisp string to the 4 byte character code. */
4166 mac_get_code_from_arg(Lisp_Object arg
, OSType defCode
)
4175 /* check type string */
4177 if (SBYTES (arg
) != 4)
4179 error ("Wrong argument: need string of length 4 for code");
4181 result
= EndianU32_BtoN (*((UInt32
*) SDATA (arg
)));
4186 /* Convert the 4 byte character code into a 4 byte string. */
4189 mac_get_object_from_code(OSType defCode
)
4191 UInt32 code
= EndianU32_NtoB (defCode
);
4193 return make_unibyte_string ((char *)&code
, 4);
4197 DEFUN ("mac-get-file-creator", Fmac_get_file_creator
, Smac_get_file_creator
, 1, 1, 0,
4198 doc
: /* Get the creator code of FILENAME as a four character string. */)
4200 Lisp_Object filename
;
4208 Lisp_Object result
= Qnil
;
4209 CHECK_STRING (filename
);
4211 if (NILP(Ffile_exists_p(filename
)) || !NILP(Ffile_directory_p(filename
))) {
4214 filename
= Fexpand_file_name (filename
, Qnil
);
4218 status
= FSPathMakeRef(SDATA(ENCODE_FILE(filename
)), &fref
, NULL
);
4220 status
= posix_pathname_to_fsspec (SDATA (ENCODE_FILE (filename
)), &fss
);
4223 if (status
== noErr
)
4226 FSCatalogInfo catalogInfo
;
4228 status
= FSGetCatalogInfo(&fref
, kFSCatInfoFinderInfo
,
4229 &catalogInfo
, NULL
, NULL
, NULL
);
4233 status
= FSpGetFInfo (&fss
, &finder_info
);
4235 if (status
== noErr
)
4238 result
= mac_get_object_from_code(((FileInfo
*)&catalogInfo
.finderInfo
)->fileCreator
);
4240 result
= mac_get_object_from_code (finder_info
.fdCreator
);
4245 if (status
!= noErr
) {
4246 error ("Error while getting file information.");
4251 DEFUN ("mac-get-file-type", Fmac_get_file_type
, Smac_get_file_type
, 1, 1, 0,
4252 doc
: /* Get the type code of FILENAME as a four character string. */)
4254 Lisp_Object filename
;
4262 Lisp_Object result
= Qnil
;
4263 CHECK_STRING (filename
);
4265 if (NILP(Ffile_exists_p(filename
)) || !NILP(Ffile_directory_p(filename
))) {
4268 filename
= Fexpand_file_name (filename
, Qnil
);
4272 status
= FSPathMakeRef(SDATA(ENCODE_FILE(filename
)), &fref
, NULL
);
4274 status
= posix_pathname_to_fsspec (SDATA (ENCODE_FILE (filename
)), &fss
);
4277 if (status
== noErr
)
4280 FSCatalogInfo catalogInfo
;
4282 status
= FSGetCatalogInfo(&fref
, kFSCatInfoFinderInfo
,
4283 &catalogInfo
, NULL
, NULL
, NULL
);
4287 status
= FSpGetFInfo (&fss
, &finder_info
);
4289 if (status
== noErr
)
4292 result
= mac_get_object_from_code(((FileInfo
*)&catalogInfo
.finderInfo
)->fileType
);
4294 result
= mac_get_object_from_code (finder_info
.fdType
);
4299 if (status
!= noErr
) {
4300 error ("Error while getting file information.");
4305 DEFUN ("mac-set-file-creator", Fmac_set_file_creator
, Smac_set_file_creator
, 1, 2, 0,
4306 doc
: /* Set creator code of file FILENAME to CODE.
4307 If non-nil, CODE must be a 4-character string. Otherwise, 'EMAx' is
4308 assumed. Return non-nil if successful. */)
4310 Lisp_Object filename
, code
;
4319 CHECK_STRING (filename
);
4321 cCode
= mac_get_code_from_arg(code
, MAC_EMACS_CREATOR_CODE
);
4323 if (NILP(Ffile_exists_p(filename
)) || !NILP(Ffile_directory_p(filename
))) {
4326 filename
= Fexpand_file_name (filename
, Qnil
);
4330 status
= FSPathMakeRef(SDATA(ENCODE_FILE(filename
)), &fref
, NULL
);
4332 status
= posix_pathname_to_fsspec (SDATA (ENCODE_FILE (filename
)), &fss
);
4335 if (status
== noErr
)
4338 FSCatalogInfo catalogInfo
;
4340 status
= FSGetCatalogInfo(&fref
, kFSCatInfoFinderInfo
,
4341 &catalogInfo
, NULL
, NULL
, &parentDir
);
4345 status
= FSpGetFInfo (&fss
, &finder_info
);
4347 if (status
== noErr
)
4350 ((FileInfo
*)&catalogInfo
.finderInfo
)->fileCreator
= cCode
;
4351 status
= FSSetCatalogInfo(&fref
, kFSCatInfoFinderInfo
, &catalogInfo
);
4352 /* TODO: on Mac OS 10.2, we need to touch the parent dir, FNNotify? */
4354 finder_info
.fdCreator
= cCode
;
4355 status
= FSpSetFInfo (&fss
, &finder_info
);
4360 if (status
!= noErr
) {
4361 error ("Error while setting creator information.");
4366 DEFUN ("mac-set-file-type", Fmac_set_file_type
, Smac_set_file_type
, 2, 2, 0,
4367 doc
: /* Set file code of file FILENAME to CODE.
4368 CODE must be a 4-character string. Return non-nil if successful. */)
4370 Lisp_Object filename
, code
;
4379 CHECK_STRING (filename
);
4381 cCode
= mac_get_code_from_arg(code
, 0); /* Default to empty code*/
4383 if (NILP(Ffile_exists_p(filename
)) || !NILP(Ffile_directory_p(filename
))) {
4386 filename
= Fexpand_file_name (filename
, Qnil
);
4390 status
= FSPathMakeRef(SDATA(ENCODE_FILE(filename
)), &fref
, NULL
);
4392 status
= posix_pathname_to_fsspec (SDATA (ENCODE_FILE (filename
)), &fss
);
4395 if (status
== noErr
)
4398 FSCatalogInfo catalogInfo
;
4400 status
= FSGetCatalogInfo(&fref
, kFSCatInfoFinderInfo
,
4401 &catalogInfo
, NULL
, NULL
, &parentDir
);
4405 status
= FSpGetFInfo (&fss
, &finder_info
);
4407 if (status
== noErr
)
4410 ((FileInfo
*)&catalogInfo
.finderInfo
)->fileType
= cCode
;
4411 status
= FSSetCatalogInfo(&fref
, kFSCatInfoFinderInfo
, &catalogInfo
);
4412 /* TODO: on Mac OS 10.2, we need to touch the parent dir, FNNotify? */
4414 finder_info
.fdType
= cCode
;
4415 status
= FSpSetFInfo (&fss
, &finder_info
);
4420 if (status
!= noErr
) {
4421 error ("Error while setting creator information.");
4427 /* Compile and execute the AppleScript SCRIPT and return the error
4428 status as function value. A zero is returned if compilation and
4429 execution is successful, in which case *RESULT is set to a Lisp
4430 string containing the resulting script value. Otherwise, the Mac
4431 error code is returned and *RESULT is set to an error Lisp string.
4432 For documentation on the MacOS scripting architecture, see Inside
4433 Macintosh - Interapplication Communications: Scripting
4437 do_applescript (script
, result
)
4438 Lisp_Object script
, *result
;
4440 AEDesc script_desc
, result_desc
, error_desc
, *desc
= NULL
;
4446 if (!as_scripting_component
)
4447 initialize_applescript();
4449 error
= AECreateDesc (typeChar
, SDATA (script
), SBYTES (script
),
4454 osaerror
= OSADoScript (as_scripting_component
, &script_desc
, kOSANullScript
,
4455 typeChar
, kOSAModeNull
, &result_desc
);
4457 if (osaerror
== noErr
)
4458 /* success: retrieve resulting script value */
4459 desc
= &result_desc
;
4460 else if (osaerror
== errOSAScriptError
)
4461 /* error executing AppleScript: retrieve error message */
4462 if (!OSAScriptError (as_scripting_component
, kOSAErrorMessage
, typeChar
,
4468 #if TARGET_API_MAC_CARBON
4469 *result
= make_uninit_string (AEGetDescDataSize (desc
));
4470 AEGetDescData (desc
, SDATA (*result
), SBYTES (*result
));
4471 #else /* not TARGET_API_MAC_CARBON */
4472 *result
= make_uninit_string (GetHandleSize (desc
->dataHandle
));
4473 memcpy (SDATA (*result
), *(desc
->dataHandle
), SBYTES (*result
));
4474 #endif /* not TARGET_API_MAC_CARBON */
4475 AEDisposeDesc (desc
);
4478 AEDisposeDesc (&script_desc
);
4484 DEFUN ("do-applescript", Fdo_applescript
, Sdo_applescript
, 1, 1, 0,
4485 doc
: /* Compile and execute AppleScript SCRIPT and return the result.
4486 If compilation and execution are successful, the resulting script
4487 value is returned as a string. Otherwise the function aborts and
4488 displays the error message returned by the AppleScript scripting
4496 CHECK_STRING (script
);
4499 status
= do_applescript (script
, &result
);
4503 else if (!STRINGP (result
))
4504 error ("AppleScript error %d", status
);
4506 error ("%s", SDATA (result
));
4510 DEFUN ("mac-file-name-to-posix", Fmac_file_name_to_posix
,
4511 Smac_file_name_to_posix
, 1, 1, 0,
4512 doc
: /* Convert Macintosh FILENAME to Posix form. */)
4514 Lisp_Object filename
;
4516 char posix_filename
[MAXPATHLEN
+1];
4518 CHECK_STRING (filename
);
4520 if (mac_to_posix_pathname (SDATA (filename
), posix_filename
, MAXPATHLEN
))
4521 return build_string (posix_filename
);
4527 DEFUN ("posix-file-name-to-mac", Fposix_file_name_to_mac
,
4528 Sposix_file_name_to_mac
, 1, 1, 0,
4529 doc
: /* Convert Posix FILENAME to Mac form. */)
4531 Lisp_Object filename
;
4533 char mac_filename
[MAXPATHLEN
+1];
4535 CHECK_STRING (filename
);
4537 if (posix_to_mac_pathname (SDATA (filename
), mac_filename
, MAXPATHLEN
))
4538 return build_string (mac_filename
);
4544 DEFUN ("mac-coerce-ae-data", Fmac_coerce_ae_data
, Smac_coerce_ae_data
, 3, 3, 0,
4545 doc
: /* Coerce Apple event data SRC-DATA of type SRC-TYPE to DST-TYPE.
4546 Each type should be a string of length 4 or the symbol
4547 `undecoded-file-name'. */)
4548 (src_type
, src_data
, dst_type
)
4549 Lisp_Object src_type
, src_data
, dst_type
;
4552 Lisp_Object result
= Qnil
;
4553 DescType src_desc_type
, dst_desc_type
;
4556 CHECK_STRING (src_data
);
4557 if (EQ (src_type
, Qundecoded_file_name
))
4558 src_desc_type
= TYPE_FILE_NAME
;
4560 src_desc_type
= mac_get_code_from_arg (src_type
, 0);
4562 if (EQ (dst_type
, Qundecoded_file_name
))
4563 dst_desc_type
= TYPE_FILE_NAME
;
4565 dst_desc_type
= mac_get_code_from_arg (dst_type
, 0);
4568 err
= AECoercePtr (src_desc_type
, SDATA (src_data
), SBYTES (src_data
),
4569 dst_desc_type
, &dst_desc
);
4572 result
= Fcdr (mac_aedesc_to_lisp (&dst_desc
));
4573 AEDisposeDesc (&dst_desc
);
4581 #if TARGET_API_MAC_CARBON
4582 static Lisp_Object Qxml
, Qmime_charset
;
4583 static Lisp_Object QNFD
, QNFKD
, QNFC
, QNFKC
, QHFS_plus_D
, QHFS_plus_C
;
4585 DEFUN ("mac-get-preference", Fmac_get_preference
, Smac_get_preference
, 1, 4, 0,
4586 doc
: /* Return the application preference value for KEY.
4587 KEY is either a string specifying a preference key, or a list of key
4588 strings. If it is a list, the (i+1)-th element is used as a key for
4589 the CFDictionary value obtained by the i-th element. Return nil if
4590 lookup is failed at some stage.
4592 Optional arg APPLICATION is an application ID string. If omitted or
4593 nil, that stands for the current application.
4595 Optional arg FORMAT specifies the data format of the return value. If
4596 omitted or nil, each Core Foundation object is converted into a
4597 corresponding Lisp object as follows:
4599 Core Foundation Lisp Tag
4600 ------------------------------------------------------------
4601 CFString Multibyte string string
4602 CFNumber Integer or float number
4603 CFBoolean Symbol (t or nil) boolean
4604 CFDate List of three integers date
4605 (cf. `current-time')
4606 CFData Unibyte string data
4607 CFArray Vector array
4608 CFDictionary Alist or hash table dictionary
4609 (depending on HASH-BOUND)
4611 If it is t, a symbol that represents the type of the original Core
4612 Foundation object is prepended. If it is `xml', the value is returned
4613 as an XML representation.
4615 Optional arg HASH-BOUND specifies which kinds of the list objects,
4616 alists or hash tables, are used as the targets of the conversion from
4617 CFDictionary. If HASH-BOUND is a negative integer or nil, always
4618 generate alists. If HASH-BOUND >= 0, generate an alist if the number
4619 of keys in the dictionary is smaller than HASH-BOUND, and a hash table
4621 (key
, application
, format
, hash_bound
)
4622 Lisp_Object key
, application
, format
, hash_bound
;
4624 CFStringRef app_id
, key_str
;
4625 CFPropertyListRef app_plist
= NULL
, plist
;
4626 Lisp_Object result
= Qnil
, tmp
;
4627 struct gcpro gcpro1
, gcpro2
;
4630 key
= Fcons (key
, Qnil
);
4634 for (tmp
= key
; CONSP (tmp
); tmp
= XCDR (tmp
))
4635 CHECK_STRING_CAR (tmp
);
4636 CHECK_LIST_END (tmp
, key
);
4638 if (!NILP (application
))
4639 CHECK_STRING (application
);
4640 CHECK_SYMBOL (format
);
4641 if (!NILP (hash_bound
))
4642 CHECK_NUMBER (hash_bound
);
4644 GCPRO2 (key
, format
);
4648 app_id
= kCFPreferencesCurrentApplication
;
4649 if (!NILP (application
))
4651 app_id
= cfstring_create_with_string (application
);
4655 if (!CFPreferencesAppSynchronize (app_id
))
4658 key_str
= cfstring_create_with_string (XCAR (key
));
4659 if (key_str
== NULL
)
4661 app_plist
= CFPreferencesCopyAppValue (key_str
, app_id
);
4662 CFRelease (key_str
);
4663 if (app_plist
== NULL
)
4667 for (key
= XCDR (key
); CONSP (key
); key
= XCDR (key
))
4669 if (CFGetTypeID (plist
) != CFDictionaryGetTypeID ())
4671 key_str
= cfstring_create_with_string (XCAR (key
));
4672 if (key_str
== NULL
)
4674 plist
= CFDictionaryGetValue (plist
, key_str
);
4675 CFRelease (key_str
);
4682 if (EQ (format
, Qxml
))
4684 CFDataRef data
= CFPropertyListCreateXMLData (NULL
, plist
);
4687 result
= cfdata_to_lisp (data
);
4692 cfproperty_list_to_lisp (plist
, EQ (format
, Qt
),
4693 NILP (hash_bound
) ? -1 : XINT (hash_bound
));
4698 CFRelease (app_plist
);
4709 static CFStringEncoding
4710 get_cfstring_encoding_from_lisp (obj
)
4713 CFStringRef iana_name
;
4714 CFStringEncoding encoding
= kCFStringEncodingInvalidId
;
4717 return kCFStringEncodingUnicode
;
4722 if (SYMBOLP (obj
) && !NILP (Fcoding_system_p (obj
)))
4724 Lisp_Object coding_spec
, plist
;
4726 coding_spec
= Fget (obj
, Qcoding_system
);
4727 plist
= XVECTOR (coding_spec
)->contents
[3];
4728 obj
= Fplist_get (XVECTOR (coding_spec
)->contents
[3], Qmime_charset
);
4732 obj
= SYMBOL_NAME (obj
);
4736 iana_name
= cfstring_create_with_string (obj
);
4739 encoding
= CFStringConvertIANACharSetNameToEncoding (iana_name
);
4740 CFRelease (iana_name
);
4747 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
4749 cfstring_create_normalized (str
, symbol
)
4754 TextEncodingVariant variant
;
4755 float initial_mag
= 0.0;
4756 CFStringRef result
= NULL
;
4758 if (EQ (symbol
, QNFD
))
4759 form
= kCFStringNormalizationFormD
;
4760 else if (EQ (symbol
, QNFKD
))
4761 form
= kCFStringNormalizationFormKD
;
4762 else if (EQ (symbol
, QNFC
))
4763 form
= kCFStringNormalizationFormC
;
4764 else if (EQ (symbol
, QNFKC
))
4765 form
= kCFStringNormalizationFormKC
;
4766 else if (EQ (symbol
, QHFS_plus_D
))
4768 variant
= kUnicodeHFSPlusDecompVariant
;
4771 else if (EQ (symbol
, QHFS_plus_C
))
4773 variant
= kUnicodeHFSPlusCompVariant
;
4779 CFMutableStringRef mut_str
= CFStringCreateMutableCopy (NULL
, 0, str
);
4783 CFStringNormalize (mut_str
, form
);
4787 else if (initial_mag
> 0.0)
4789 UnicodeToTextInfo uni
= NULL
;
4792 UniChar
*in_text
, *buffer
= NULL
, *out_buf
= NULL
;
4793 OSStatus err
= noErr
;
4794 ByteCount out_read
, out_size
, out_len
;
4796 map
.unicodeEncoding
= CreateTextEncoding (kTextEncodingUnicodeDefault
,
4798 kTextEncodingDefaultFormat
);
4799 map
.otherEncoding
= CreateTextEncoding (kTextEncodingUnicodeDefault
,
4801 kTextEncodingDefaultFormat
);
4802 map
.mappingVersion
= kUnicodeUseLatestMapping
;
4804 length
= CFStringGetLength (str
);
4805 out_size
= (int)((float)length
* initial_mag
) * sizeof (UniChar
);
4809 in_text
= (UniChar
*)CFStringGetCharactersPtr (str
);
4810 if (in_text
== NULL
)
4812 buffer
= xmalloc (sizeof (UniChar
) * length
);
4813 CFStringGetCharacters (str
, CFRangeMake (0, length
), buffer
);
4818 err
= CreateUnicodeToTextInfo (&map
, &uni
);
4819 while (err
== noErr
)
4821 out_buf
= xmalloc (out_size
);
4822 err
= ConvertFromUnicodeToText (uni
, length
* sizeof (UniChar
),
4824 kUnicodeDefaultDirectionMask
,
4825 0, NULL
, NULL
, NULL
,
4826 out_size
, &out_read
, &out_len
,
4828 if (err
== noErr
&& out_read
< length
* sizeof (UniChar
))
4837 result
= CFStringCreateWithCharacters (NULL
, out_buf
,
4838 out_len
/ sizeof (UniChar
));
4840 DisposeUnicodeToTextInfo (&uni
);
4856 DEFUN ("mac-code-convert-string", Fmac_code_convert_string
, Smac_code_convert_string
, 3, 4, 0,
4857 doc
: /* Convert STRING from SOURCE encoding to TARGET encoding.
4858 The conversion is performed using the converter provided by the system.
4859 Each encoding is specified by either a coding system symbol, a mime
4860 charset string, or an integer as a CFStringEncoding value. An encoding
4861 of nil means UTF-16 in native byte order, no byte order mark.
4862 On Mac OS X 10.2 and later, you can do Unicode Normalization by
4863 specifying the optional argument NORMALIZATION-FORM with a symbol NFD,
4864 NFKD, NFC, NFKC, HFS+D, or HFS+C.
4865 On successful conversion, return the result string, else return nil. */)
4866 (string
, source
, target
, normalization_form
)
4867 Lisp_Object string
, source
, target
, normalization_form
;
4869 Lisp_Object result
= Qnil
;
4870 struct gcpro gcpro1
, gcpro2
, gcpro3
, gcpro4
;
4871 CFStringEncoding src_encoding
, tgt_encoding
;
4872 CFStringRef str
= NULL
;
4874 CHECK_STRING (string
);
4875 if (!INTEGERP (source
) && !STRINGP (source
))
4876 CHECK_SYMBOL (source
);
4877 if (!INTEGERP (target
) && !STRINGP (target
))
4878 CHECK_SYMBOL (target
);
4879 CHECK_SYMBOL (normalization_form
);
4881 GCPRO4 (string
, source
, target
, normalization_form
);
4885 src_encoding
= get_cfstring_encoding_from_lisp (source
);
4886 tgt_encoding
= get_cfstring_encoding_from_lisp (target
);
4888 /* We really want string_to_unibyte, but since it doesn't exist yet, we
4889 use string_as_unibyte which works as well, except for the fact that
4890 it's too permissive (it doesn't check that the multibyte string only
4891 contain single-byte chars). */
4892 string
= Fstring_as_unibyte (string
);
4893 if (src_encoding
!= kCFStringEncodingInvalidId
4894 && tgt_encoding
!= kCFStringEncodingInvalidId
)
4895 str
= CFStringCreateWithBytes (NULL
, SDATA (string
), SBYTES (string
),
4896 src_encoding
, !NILP (source
));
4897 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
4900 CFStringRef saved_str
= str
;
4902 str
= cfstring_create_normalized (saved_str
, normalization_form
);
4903 CFRelease (saved_str
);
4908 CFIndex str_len
, buf_len
;
4910 str_len
= CFStringGetLength (str
);
4911 if (CFStringGetBytes (str
, CFRangeMake (0, str_len
), tgt_encoding
, 0,
4912 !NILP (target
), NULL
, 0, &buf_len
) == str_len
)
4914 result
= make_uninit_string (buf_len
);
4915 CFStringGetBytes (str
, CFRangeMake (0, str_len
), tgt_encoding
, 0,
4916 !NILP (target
), SDATA (result
), buf_len
, NULL
);
4928 DEFUN ("mac-process-hi-command", Fmac_process_hi_command
, Smac_process_hi_command
, 1, 1, 0,
4929 doc
: /* Send a HI command whose ID is COMMAND-ID to the command chain.
4930 COMMAND-ID must be a 4-character string. Some common command IDs are
4931 defined in the Carbon Event Manager. */)
4933 Lisp_Object command_id
;
4938 bzero (&command
, sizeof (HICommand
));
4939 command
.commandID
= mac_get_code_from_arg (command_id
, 0);
4942 err
= ProcessHICommand (&command
);
4946 error ("HI command (command ID: '%s') not handled.", SDATA (command_id
));
4951 #endif /* TARGET_API_MAC_CARBON */
4955 mac_get_system_locale ()
4963 lang
= GetScriptVariable (smSystemScript
, smScriptLang
);
4964 region
= GetScriptManagerVariable (smRegionCode
);
4965 err
= LocaleRefFromLangOrRegionCode (lang
, region
, &locale
);
4967 err
= LocaleRefGetPartString (locale
, kLocaleAllPartsMask
,
4970 return build_string (str
);
4978 extern int inhibit_window_system
;
4979 extern int noninteractive
;
4981 /* Unlike in X11, window events in Carbon do not come from sockets.
4982 So we cannot simply use `select' to monitor two kinds of inputs:
4983 window events and process outputs. We emulate such functionality
4984 by regarding fd 0 as the window event channel and simultaneously
4985 monitoring both kinds of input channels. It is implemented by
4986 dividing into some cases:
4987 1. The window event channel is not involved.
4989 2. Sockets are not involved.
4990 -> Use ReceiveNextEvent.
4991 3. [If SELECT_USE_CFSOCKET is set]
4992 Only the window event channel and socket read/write channels are
4993 involved, and timeout is not too short (greater than
4994 SELECT_TIMEOUT_THRESHOLD_RUNLOOP seconds).
4995 -> Create CFSocket for each socket and add it into the current
4996 event RunLoop so that the current event loop gets quit when
4997 the socket becomes ready. Then ReceiveNextEvent can wait for
4998 both kinds of inputs.
5000 -> Periodically poll the window input channel while repeatedly
5001 executing `select' with a short timeout
5002 (SELECT_POLLING_PERIOD_USEC microseconds). */
5004 #ifndef SELECT_USE_CFSOCKET
5005 #define SELECT_USE_CFSOCKET 1
5008 #define SELECT_POLLING_PERIOD_USEC 100000
5009 #if SELECT_USE_CFSOCKET
5010 #define SELECT_TIMEOUT_THRESHOLD_RUNLOOP 0.2
5013 socket_callback (s
, type
, address
, data
, info
)
5015 CFSocketCallBackType type
;
5020 int fd
= CFSocketGetNative (s
);
5021 SELECT_TYPE
*ofds
= (SELECT_TYPE
*)info
;
5023 if ((type
== kCFSocketReadCallBack
&& FD_ISSET (fd
, &ofds
[0]))
5024 || (type
== kCFSocketConnectCallBack
&& FD_ISSET (fd
, &ofds
[1])))
5025 QuitEventLoop (GetCurrentEventLoop ());
5027 #endif /* SELECT_USE_CFSOCKET */
5030 select_and_poll_event (nfds
, rfds
, wfds
, efds
, timeout
)
5032 SELECT_TYPE
*rfds
, *wfds
, *efds
;
5033 EMACS_TIME
*timeout
;
5035 OSStatus err
= noErr
;
5038 /* Try detect_input_pending before ReceiveNextEvent in the same
5039 BLOCK_INPUT block, in case that some input has already been read
5042 ENABLE_WAKEUP_FROM_RNE
;
5043 if (!detect_input_pending ())
5045 EMACS_TIME select_timeout
;
5046 EventTimeout timeoutval
=
5048 ? (EMACS_SECS (*timeout
) * kEventDurationSecond
5049 + EMACS_USECS (*timeout
) * kEventDurationMicrosecond
)
5050 : kEventDurationForever
);
5052 EMACS_SET_SECS_USECS (select_timeout
, 0, 0);
5053 r
= select (nfds
, rfds
, wfds
, efds
, &select_timeout
);
5054 if (timeoutval
== 0.0)
5055 err
= eventLoopTimedOutErr
;
5059 mac_prepare_for_quickdraw (NULL
);
5061 err
= ReceiveNextEvent (0, NULL
, timeoutval
,
5062 kEventLeaveInQueue
, NULL
);
5065 DISABLE_WAKEUP_FROM_RNE
;
5070 else if (err
== noErr
)
5072 /* Pretend that `select' is interrupted by a signal. */
5073 detect_input_pending ();
5082 sys_select (nfds
, rfds
, wfds
, efds
, timeout
)
5084 SELECT_TYPE
*rfds
, *wfds
, *efds
;
5085 EMACS_TIME
*timeout
;
5087 OSStatus err
= noErr
;
5089 EMACS_TIME select_timeout
;
5090 static SELECT_TYPE ofds
[3];
5092 if (inhibit_window_system
|| noninteractive
5093 || nfds
< 1 || rfds
== NULL
|| !FD_ISSET (0, rfds
))
5094 return select (nfds
, rfds
, wfds
, efds
, timeout
);
5108 EventTimeout timeoutval
=
5110 ? (EMACS_SECS (*timeout
) * kEventDurationSecond
5111 + EMACS_USECS (*timeout
) * kEventDurationMicrosecond
)
5112 : kEventDurationForever
);
5114 FD_SET (0, rfds
); /* sentinel */
5119 while (!(FD_ISSET (nfds
, rfds
) || (wfds
&& FD_ISSET (nfds
, wfds
))));
5124 return select_and_poll_event (nfds
, rfds
, wfds
, efds
, timeout
);
5126 /* Avoid initial overhead of RunLoop setup for the case that
5127 some input is already available. */
5128 EMACS_SET_SECS_USECS (select_timeout
, 0, 0);
5129 r
= select_and_poll_event (nfds
, rfds
, wfds
, efds
, &select_timeout
);
5130 if (r
!= 0 || timeoutval
== 0.0)
5137 #if SELECT_USE_CFSOCKET
5138 if (timeoutval
> 0 && timeoutval
<= SELECT_TIMEOUT_THRESHOLD_RUNLOOP
)
5139 goto poll_periodically
;
5141 /* Try detect_input_pending before ReceiveNextEvent in the same
5142 BLOCK_INPUT block, in case that some input has already been
5143 read asynchronously. */
5145 ENABLE_WAKEUP_FROM_RNE
;
5146 if (!detect_input_pending ())
5149 CFRunLoopRef runloop
=
5150 (CFRunLoopRef
) GetCFRunLoopFromEventLoop (GetCurrentEventLoop ());
5151 static const CFSocketContext context
= {0, ofds
, NULL
, NULL
, NULL
};
5152 static CFMutableDictionaryRef sources
;
5154 if (sources
== NULL
)
5156 CFDictionaryCreateMutable (NULL
, 0, NULL
,
5157 &kCFTypeDictionaryValueCallBacks
);
5159 for (minfd
= 1; ; minfd
++) /* nfds-1 works as a sentinel. */
5160 if (FD_ISSET (minfd
, rfds
) || (wfds
&& FD_ISSET (minfd
, wfds
)))
5163 for (fd
= minfd
; fd
< nfds
; fd
++)
5164 if (FD_ISSET (fd
, rfds
) || (wfds
&& FD_ISSET (fd
, wfds
)))
5166 void *key
= (void *) fd
;
5167 CFRunLoopSourceRef source
=
5168 (CFRunLoopSourceRef
) CFDictionaryGetValue (sources
, key
);
5172 CFSocketRef socket
=
5173 CFSocketCreateWithNative (NULL
, fd
,
5174 (kCFSocketReadCallBack
5175 | kCFSocketConnectCallBack
),
5176 socket_callback
, &context
);
5180 source
= CFSocketCreateRunLoopSource (NULL
, socket
, 0);
5184 CFDictionaryAddValue (sources
, key
, source
);
5187 CFRunLoopAddSource (runloop
, source
, kCFRunLoopDefaultMode
);
5191 mac_prepare_for_quickdraw (NULL
);
5193 err
= ReceiveNextEvent (0, NULL
, timeoutval
,
5194 kEventLeaveInQueue
, NULL
);
5196 for (fd
= minfd
; fd
< nfds
; fd
++)
5197 if (FD_ISSET (fd
, rfds
) || (wfds
&& FD_ISSET (fd
, wfds
)))
5199 void *key
= (void *) fd
;
5200 CFRunLoopSourceRef source
=
5201 (CFRunLoopSourceRef
) CFDictionaryGetValue (sources
, key
);
5203 CFRunLoopRemoveSource (runloop
, source
, kCFRunLoopDefaultMode
);
5206 DISABLE_WAKEUP_FROM_RNE
;
5209 if (err
== noErr
|| err
== eventLoopQuitErr
)
5211 EMACS_SET_SECS_USECS (select_timeout
, 0, 0);
5212 return select_and_poll_event (nfds
, rfds
, wfds
, efds
,
5222 #endif /* SELECT_USE_CFSOCKET */
5227 EMACS_TIME end_time
, now
, remaining_time
;
5231 remaining_time
= *timeout
;
5232 EMACS_GET_TIME (now
);
5233 EMACS_ADD_TIME (end_time
, now
, remaining_time
);
5238 EMACS_SET_SECS_USECS (select_timeout
, 0, SELECT_POLLING_PERIOD_USEC
);
5239 if (timeout
&& EMACS_TIME_LT (remaining_time
, select_timeout
))
5240 select_timeout
= remaining_time
;
5241 r
= select_and_poll_event (nfds
, rfds
, wfds
, efds
, &select_timeout
);
5253 EMACS_GET_TIME (now
);
5254 EMACS_SUB_TIME (remaining_time
, end_time
, now
);
5257 while (!timeout
|| EMACS_TIME_LT (now
, end_time
));
5259 EMACS_SET_SECS_USECS (select_timeout
, 0, 0);
5260 return select_and_poll_event (nfds
, rfds
, wfds
, efds
, &select_timeout
);
5264 /* Set up environment variables so that Emacs can correctly find its
5265 support files when packaged as an application bundle. Directories
5266 placed in /usr/local/share/emacs/<emacs-version>/, /usr/local/bin,
5267 and /usr/local/libexec/emacs/<emacs-version>/<system-configuration>
5268 by `make install' by default can instead be placed in
5269 .../Emacs.app/Contents/Resources/ and
5270 .../Emacs.app/Contents/MacOS/. Each of these environment variables
5271 is changed only if it is not already set. Presumably if the user
5272 sets an environment variable, he will want to use files in his path
5273 instead of ones in the application bundle. */
5275 init_mac_osx_environment ()
5279 CFStringRef cf_app_bundle_pathname
;
5280 int app_bundle_pathname_len
;
5281 char *app_bundle_pathname
;
5285 /* Initialize locale related variables. */
5286 mac_system_script_code
=
5287 (ScriptCode
) GetScriptManagerVariable (smSysScript
);
5288 Vmac_system_locale
= mac_get_system_locale ();
5290 /* Fetch the pathname of the application bundle as a C string into
5291 app_bundle_pathname. */
5293 bundle
= CFBundleGetMainBundle ();
5294 if (!bundle
|| CFBundleGetIdentifier (bundle
) == NULL
)
5296 /* We could not find the bundle identifier. For now, prevent
5297 the fatal error by bringing it up in the terminal. */
5298 inhibit_window_system
= 1;
5302 bundleURL
= CFBundleCopyBundleURL (bundle
);
5306 cf_app_bundle_pathname
= CFURLCopyFileSystemPath (bundleURL
,
5307 kCFURLPOSIXPathStyle
);
5308 app_bundle_pathname_len
= CFStringGetLength (cf_app_bundle_pathname
);
5309 app_bundle_pathname
= (char *) alloca (app_bundle_pathname_len
+ 1);
5311 if (!CFStringGetCString (cf_app_bundle_pathname
,
5312 app_bundle_pathname
,
5313 app_bundle_pathname_len
+ 1,
5314 kCFStringEncodingISOLatin1
))
5316 CFRelease (cf_app_bundle_pathname
);
5320 CFRelease (cf_app_bundle_pathname
);
5322 /* P should have sufficient room for the pathname of the bundle plus
5323 the subpath in it leading to the respective directories. Q
5324 should have three times that much room because EMACSLOADPATH can
5325 have the value "<path to lisp dir>:<path to leim dir>:<path to
5327 p
= (char *) alloca (app_bundle_pathname_len
+ 50);
5328 q
= (char *) alloca (3 * app_bundle_pathname_len
+ 150);
5329 if (!getenv ("EMACSLOADPATH"))
5333 strcpy (p
, app_bundle_pathname
);
5334 strcat (p
, "/Contents/Resources/lisp");
5335 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
5338 strcpy (p
, app_bundle_pathname
);
5339 strcat (p
, "/Contents/Resources/leim");
5340 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
5347 strcpy (p
, app_bundle_pathname
);
5348 strcat (p
, "/Contents/Resources/site-lisp");
5349 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
5357 setenv ("EMACSLOADPATH", q
, 1);
5360 if (!getenv ("EMACSPATH"))
5364 strcpy (p
, app_bundle_pathname
);
5365 strcat (p
, "/Contents/MacOS/libexec");
5366 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
5369 strcpy (p
, app_bundle_pathname
);
5370 strcat (p
, "/Contents/MacOS/bin");
5371 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
5379 setenv ("EMACSPATH", q
, 1);
5382 if (!getenv ("EMACSDATA"))
5384 strcpy (p
, app_bundle_pathname
);
5385 strcat (p
, "/Contents/Resources/etc");
5386 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
5387 setenv ("EMACSDATA", p
, 1);
5390 if (!getenv ("EMACSDOC"))
5392 strcpy (p
, app_bundle_pathname
);
5393 strcat (p
, "/Contents/Resources/etc");
5394 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
5395 setenv ("EMACSDOC", p
, 1);
5398 if (!getenv ("INFOPATH"))
5400 strcpy (p
, app_bundle_pathname
);
5401 strcat (p
, "/Contents/Resources/info");
5402 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
5403 setenv ("INFOPATH", p
, 1);
5406 #endif /* MAC_OSX */
5408 #if TARGET_API_MAC_CARBON
5410 mac_wakeup_from_rne ()
5412 if (wakeup_from_rne_enabled_p
)
5413 /* Post a harmless event so as to wake up from
5414 ReceiveNextEvent. */
5415 mac_post_mouse_moved_event ();
5422 Qundecoded_file_name
= intern ("undecoded-file-name");
5423 staticpro (&Qundecoded_file_name
);
5425 #if TARGET_API_MAC_CARBON
5426 Qstring
= intern ("string"); staticpro (&Qstring
);
5427 Qnumber
= intern ("number"); staticpro (&Qnumber
);
5428 Qboolean
= intern ("boolean"); staticpro (&Qboolean
);
5429 Qdate
= intern ("date"); staticpro (&Qdate
);
5430 Qdata
= intern ("data"); staticpro (&Qdata
);
5431 Qarray
= intern ("array"); staticpro (&Qarray
);
5432 Qdictionary
= intern ("dictionary"); staticpro (&Qdictionary
);
5434 Qxml
= intern ("xml");
5437 Qmime_charset
= intern ("mime-charset");
5438 staticpro (&Qmime_charset
);
5440 QNFD
= intern ("NFD"); staticpro (&QNFD
);
5441 QNFKD
= intern ("NFKD"); staticpro (&QNFKD
);
5442 QNFC
= intern ("NFC"); staticpro (&QNFC
);
5443 QNFKC
= intern ("NFKC"); staticpro (&QNFKC
);
5444 QHFS_plus_D
= intern ("HFS+D"); staticpro (&QHFS_plus_D
);
5445 QHFS_plus_C
= intern ("HFS+C"); staticpro (&QHFS_plus_C
);
5451 for (i
= 0; i
< sizeof (ae_attr_table
) / sizeof (ae_attr_table
[0]); i
++)
5453 ae_attr_table
[i
].symbol
= intern (ae_attr_table
[i
].name
);
5454 staticpro (&ae_attr_table
[i
].symbol
);
5458 defsubr (&Smac_coerce_ae_data
);
5459 #if TARGET_API_MAC_CARBON
5460 defsubr (&Smac_get_preference
);
5461 defsubr (&Smac_code_convert_string
);
5462 defsubr (&Smac_process_hi_command
);
5465 defsubr (&Smac_set_file_creator
);
5466 defsubr (&Smac_set_file_type
);
5467 defsubr (&Smac_get_file_creator
);
5468 defsubr (&Smac_get_file_type
);
5469 defsubr (&Sdo_applescript
);
5470 defsubr (&Smac_file_name_to_posix
);
5471 defsubr (&Sposix_file_name_to_mac
);
5473 DEFVAR_INT ("mac-system-script-code", &mac_system_script_code
,
5474 doc
: /* The system script code. */);
5475 mac_system_script_code
= (ScriptCode
) GetScriptManagerVariable (smSysScript
);
5477 DEFVAR_LISP ("mac-system-locale", &Vmac_system_locale
,
5478 doc
: /* The system locale identifier string.
5479 This is not a POSIX locale ID, but an ICU locale ID. So encoding
5480 information is not included. */);
5481 Vmac_system_locale
= mac_get_system_locale ();
5484 /* arch-tag: 29d30c1f-0c6b-4f88-8a6d-0558d7f9dbff
5485 (do not change this comment) */