1 /* Unix emulation routines for GNU Emacs on the Mac OS.
2 Copyright (C) 2000, 2001, 2002, 2003, 2004,
3 2005, 2006 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). */
33 #include "sysselect.h"
34 #include "blockinput.h"
40 #if !TARGET_API_MAC_CARBON
43 #include <TextUtils.h>
45 #include <Resources.h>
50 #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 static OSErr posix_pathname_to_fsspec
P_ ((const char *, FSSpec
*));
83 static OSErr fsspec_to_posix_pathname
P_ ((const FSSpec
*, char *, int));
85 /* When converting from Mac to Unix pathnames, /'s in folder names are
86 converted to :'s. This function, used in copying folder names,
87 performs a strncat and converts all character a to b in the copy of
88 the string s2 appended to the end of s1. */
91 string_cat_and_replace (char *s1
, const char *s2
, int n
, char a
, char b
)
99 for (i
= 0; i
< l2
; i
++)
108 /* Convert a Mac pathname to Posix form. A Mac full pathname is one
109 that does not begin with a ':' and contains at least one ':'. A Mac
110 full pathname causes a '/' to be prepended to the Posix pathname.
111 The algorithm for the rest of the pathname is as follows:
112 For each segment between two ':',
113 if it is non-null, copy as is and then add a '/' at the end,
114 otherwise, insert a "../" into the Posix pathname.
115 Returns 1 if successful; 0 if fails. */
118 mac_to_posix_pathname (const char *mfn
, char *ufn
, int ufnbuflen
)
120 const char *p
, *q
, *pe
;
127 p
= strchr (mfn
, ':');
128 if (p
!= 0 && p
!= mfn
) /* full pathname */
135 pe
= mfn
+ strlen (mfn
);
142 { /* two consecutive ':' */
143 if (strlen (ufn
) + 3 >= ufnbuflen
)
149 if (strlen (ufn
) + (q
- p
) + 1 >= ufnbuflen
)
151 string_cat_and_replace (ufn
, p
, q
- p
, '/', ':');
158 if (strlen (ufn
) + (pe
- p
) >= ufnbuflen
)
160 string_cat_and_replace (ufn
, p
, pe
- p
, '/', ':');
161 /* no separator for last one */
170 extern char *get_temp_dir_name ();
173 /* Convert a Posix pathname to Mac form. Approximately reverse of the
174 above in algorithm. */
177 posix_to_mac_pathname (const char *ufn
, char *mfn
, int mfnbuflen
)
179 const char *p
, *q
, *pe
;
180 char expanded_pathname
[MAXPATHLEN
+1];
189 /* Check for and handle volume names. Last comparison: strangely
190 somewhere "/.emacs" is passed. A temporary fix for now. */
191 if (*p
== '/' && strchr (p
+1, '/') == NULL
&& strcmp (p
, "/.emacs") != 0)
193 if (strlen (p
) + 1 > mfnbuflen
)
200 /* expand to emacs dir found by init_emacs_passwd_dir */
201 if (strncmp (p
, "~emacs/", 7) == 0)
203 struct passwd
*pw
= getpwnam ("emacs");
205 if (strlen (pw
->pw_dir
) + strlen (p
) > MAXPATHLEN
)
207 strcpy (expanded_pathname
, pw
->pw_dir
);
208 strcat (expanded_pathname
, p
);
209 p
= expanded_pathname
;
210 /* now p points to the pathname with emacs dir prefix */
212 else if (strncmp (p
, "/tmp/", 5) == 0)
214 char *t
= get_temp_dir_name ();
216 if (strlen (t
) + strlen (p
) > MAXPATHLEN
)
218 strcpy (expanded_pathname
, t
);
219 strcat (expanded_pathname
, p
);
220 p
= expanded_pathname
;
221 /* now p points to the pathname with emacs dir prefix */
223 else if (*p
!= '/') /* relative pathname */
235 if (q
- p
== 2 && *p
== '.' && *(p
+1) == '.')
237 if (strlen (mfn
) + 1 >= mfnbuflen
)
243 if (strlen (mfn
) + (q
- p
) + 1 >= mfnbuflen
)
245 string_cat_and_replace (mfn
, p
, q
- p
, ':', '/');
252 if (strlen (mfn
) + (pe
- p
) >= mfnbuflen
)
254 string_cat_and_replace (mfn
, p
, pe
- p
, ':', '/');
263 /***********************************************************************
264 Conversions on Apple event objects
265 ***********************************************************************/
267 static Lisp_Object Qundecoded_file_name
;
270 mac_aelist_to_lisp (desc_list
)
271 AEDescList
*desc_list
;
275 Lisp_Object result
, elem
;
281 err
= AECountItems (desc_list
, &count
);
287 err
= AESizeOfNthItem (desc_list
, count
, &desc_type
, &size
);
294 err
= AEGetNthDesc (desc_list
, count
, typeWildCard
,
298 elem
= mac_aelist_to_lisp (&desc
);
299 AEDisposeDesc (&desc
);
303 if (desc_type
== typeNull
)
307 elem
= make_uninit_string (size
);
308 err
= AEGetNthPtr (desc_list
, count
, typeWildCard
, &keyword
,
309 &desc_type
, SDATA (elem
), size
, &size
);
313 desc_type
= EndianU32_NtoB (desc_type
);
314 elem
= Fcons (make_unibyte_string ((char *) &desc_type
, 4), elem
);
320 else if (desc_list
->descriptorType
!= typeAEList
)
322 keyword
= EndianU32_NtoB (keyword
);
323 elem
= Fcons (make_unibyte_string ((char *) &keyword
, 4), elem
);
326 result
= Fcons (elem
, result
);
330 desc_type
= EndianU32_NtoB (desc_list
->descriptorType
);
331 return Fcons (make_unibyte_string ((char *) &desc_type
, 4), result
);
335 mac_aedesc_to_lisp (desc
)
339 DescType desc_type
= desc
->descriptorType
;
351 return mac_aelist_to_lisp (desc
);
353 /* The following one is much simpler, but creates and disposes
354 of Apple event descriptors many times. */
361 err
= AECountItems (desc
, &count
);
367 err
= AEGetNthDesc (desc
, count
, typeWildCard
, &keyword
, &desc1
);
370 elem
= mac_aedesc_to_lisp (&desc1
);
371 AEDisposeDesc (&desc1
);
372 if (desc_type
!= typeAEList
)
374 keyword
= EndianU32_NtoB (keyword
);
375 elem
= Fcons (make_unibyte_string ((char *) &keyword
, 4), elem
);
377 result
= Fcons (elem
, result
);
385 #if TARGET_API_MAC_CARBON
386 result
= make_uninit_string (AEGetDescDataSize (desc
));
387 err
= AEGetDescData (desc
, SDATA (result
), SBYTES (result
));
389 result
= make_uninit_string (GetHandleSize (desc
->dataHandle
));
390 memcpy (SDATA (result
), *(desc
->dataHandle
), SBYTES (result
));
398 desc_type
= EndianU32_NtoB (desc_type
);
399 return Fcons (make_unibyte_string ((char *) &desc_type
, 4), result
);
403 mac_coerce_file_name_ptr (type_code
, data_ptr
, data_size
,
404 to_type
, handler_refcon
, result
)
406 const void *data_ptr
;
414 if (type_code
== typeNull
)
415 err
= errAECoercionFail
;
416 else if (type_code
== to_type
|| to_type
== typeWildCard
)
417 err
= AECreateDesc (TYPE_FILE_NAME
, data_ptr
, data_size
, result
);
418 else if (type_code
== TYPE_FILE_NAME
)
419 /* Coercion from undecoded file name. */
424 CFDataRef data
= NULL
;
426 str
= CFStringCreateWithBytes (NULL
, data_ptr
, data_size
,
427 kCFStringEncodingUTF8
, false);
430 url
= CFURLCreateWithFileSystemPath (NULL
, str
,
431 kCFURLPOSIXPathStyle
, false);
436 data
= CFURLCreateData (NULL
, url
, kCFStringEncodingUTF8
, true);
441 err
= AECoercePtr (typeFileURL
, CFDataGetBytePtr (data
),
442 CFDataGetLength (data
), to_type
, result
);
451 buf
= xmalloc (data_size
+ 1);
454 memcpy (buf
, data_ptr
, data_size
);
455 buf
[data_size
] = '\0';
456 err
= posix_pathname_to_fsspec (buf
, &fs
);
462 err
= AECoercePtr (typeFSS
, &fs
, sizeof (FSSpec
), to_type
, result
);
465 else if (to_type
== TYPE_FILE_NAME
)
466 /* Coercion to undecoded file name. */
470 CFStringRef str
= NULL
;
471 CFDataRef data
= NULL
;
473 if (type_code
== typeFileURL
)
474 url
= CFURLCreateWithBytes (NULL
, data_ptr
, data_size
,
475 kCFStringEncodingUTF8
, NULL
);
482 err
= AECoercePtr (type_code
, data_ptr
, data_size
,
486 size
= AEGetDescDataSize (&desc
);
487 buf
= xmalloc (size
);
490 err
= AEGetDescData (&desc
, buf
, size
);
492 url
= CFURLCreateWithBytes (NULL
, buf
, size
,
493 kCFStringEncodingUTF8
, NULL
);
496 AEDisposeDesc (&desc
);
501 str
= CFURLCopyFileSystemPath (url
, kCFURLPOSIXPathStyle
);
506 data
= CFStringCreateExternalRepresentation (NULL
, str
,
507 kCFStringEncodingUTF8
,
513 err
= AECreateDesc (TYPE_FILE_NAME
, CFDataGetBytePtr (data
),
514 CFDataGetLength (data
), result
);
518 char file_name
[MAXPATHLEN
];
520 if (type_code
== typeFSS
&& data_size
== sizeof (FSSpec
))
521 err
= fsspec_to_posix_pathname (data_ptr
, file_name
,
522 sizeof (file_name
) - 1);
528 err
= AECoercePtr (type_code
, data_ptr
, data_size
, typeFSS
, &desc
);
531 #if TARGET_API_MAC_CARBON
532 err
= AEGetDescData (&desc
, &fs
, sizeof (FSSpec
));
534 fs
= *(FSSpec
*)(*(desc
.dataHandle
));
537 err
= fsspec_to_posix_pathname (&fs
, file_name
,
538 sizeof (file_name
) - 1);
539 AEDisposeDesc (&desc
);
543 err
= AECreateDesc (TYPE_FILE_NAME
, file_name
,
544 strlen (file_name
), result
);
551 return errAECoercionFail
;
556 mac_coerce_file_name_desc (from_desc
, to_type
, handler_refcon
, result
)
557 const AEDesc
*from_desc
;
563 DescType from_type
= from_desc
->descriptorType
;
565 if (from_type
== typeNull
)
566 err
= errAECoercionFail
;
567 else if (from_type
== to_type
|| to_type
== typeWildCard
)
568 err
= AEDuplicateDesc (from_desc
, result
);
574 #if TARGET_API_MAC_CARBON
575 data_size
= AEGetDescDataSize (from_desc
);
577 data_size
= GetHandleSize (from_desc
->dataHandle
);
579 data_ptr
= xmalloc (data_size
);
582 #if TARGET_API_MAC_CARBON
583 err
= AEGetDescData (from_desc
, data_ptr
, data_size
);
585 memcpy (data_ptr
, *(from_desc
->dataHandle
), data_size
);
588 err
= mac_coerce_file_name_ptr (from_type
, data_ptr
,
590 handler_refcon
, result
);
598 return errAECoercionFail
;
603 init_coercion_handler ()
607 static AECoercePtrUPP coerce_file_name_ptrUPP
= NULL
;
608 static AECoerceDescUPP coerce_file_name_descUPP
= NULL
;
610 if (coerce_file_name_ptrUPP
== NULL
)
612 coerce_file_name_ptrUPP
= NewAECoercePtrUPP (mac_coerce_file_name_ptr
);
613 coerce_file_name_descUPP
= NewAECoerceDescUPP (mac_coerce_file_name_desc
);
616 err
= AEInstallCoercionHandler (TYPE_FILE_NAME
, typeWildCard
,
617 (AECoercionHandlerUPP
)
618 coerce_file_name_ptrUPP
, 0, false, false);
620 err
= AEInstallCoercionHandler (typeWildCard
, TYPE_FILE_NAME
,
621 (AECoercionHandlerUPP
)
622 coerce_file_name_ptrUPP
, 0, false, false);
624 err
= AEInstallCoercionHandler (TYPE_FILE_NAME
, typeWildCard
,
625 coerce_file_name_descUPP
, 0, true, false);
627 err
= AEInstallCoercionHandler (typeWildCard
, TYPE_FILE_NAME
,
628 coerce_file_name_descUPP
, 0, true, false);
632 #if TARGET_API_MAC_CARBON
634 create_apple_event_from_event_ref (event
, num_params
, names
, types
, result
)
637 EventParamName
*names
;
638 EventParamType
*types
;
642 static const ProcessSerialNumber psn
= {0, kCurrentProcess
};
643 AEAddressDesc address_desc
;
649 err
= AECreateDesc (typeProcessSerialNumber
, &psn
,
650 sizeof (ProcessSerialNumber
), &address_desc
);
653 err
= AECreateAppleEvent (0, 0, /* Dummy class and ID. */
654 &address_desc
, /* NULL is not allowed
655 on Mac OS Classic. */
656 kAutoGenerateReturnID
,
657 kAnyTransactionID
, result
);
658 AEDisposeDesc (&address_desc
);
663 for (i
= 0; i
< num_params
; i
++)
667 case typeCFStringRef
:
668 err
= GetEventParameter (event
, names
[i
], typeCFStringRef
, NULL
,
669 sizeof (CFStringRef
), NULL
, &string
);
672 data
= CFStringCreateExternalRepresentation (NULL
, string
,
673 kCFStringEncodingUTF8
,
677 /* typeUTF8Text is not available on Mac OS X 10.1. */
678 AEPutParamPtr (result
, names
[i
], 'utf8',
679 CFDataGetBytePtr (data
), CFDataGetLength (data
));
685 err
= GetEventParameter (event
, names
[i
], types
[i
], NULL
,
689 buf
= xmalloc (size
);
692 err
= GetEventParameter (event
, names
[i
], types
[i
], NULL
,
695 AEPutParamPtr (result
, names
[i
], types
[i
], buf
, size
);
705 /***********************************************************************
706 Conversion between Lisp and Core Foundation objects
707 ***********************************************************************/
709 #if TARGET_API_MAC_CARBON
710 static Lisp_Object Qstring
, Qnumber
, Qboolean
, Qdate
, Qdata
;
711 static Lisp_Object Qarray
, Qdictionary
;
713 struct cfdict_context
716 int with_tag
, hash_bound
;
719 /* C string to CFString. */
722 cfstring_create_with_utf8_cstring (c_str
)
727 str
= CFStringCreateWithCString (NULL
, c_str
, kCFStringEncodingUTF8
);
729 /* Failed to interpret as UTF 8. Fall back on Mac Roman. */
730 str
= CFStringCreateWithCString (NULL
, c_str
, kCFStringEncodingMacRoman
);
736 /* Lisp string to CFString. */
739 cfstring_create_with_string (s
)
742 CFStringRef string
= NULL
;
744 if (STRING_MULTIBYTE (s
))
746 char *p
, *end
= SDATA (s
) + SBYTES (s
);
748 for (p
= SDATA (s
); p
< end
; p
++)
751 s
= ENCODE_UTF_8 (s
);
754 string
= CFStringCreateWithBytes (NULL
, SDATA (s
), SBYTES (s
),
755 kCFStringEncodingUTF8
, false);
759 /* Failed to interpret as UTF 8. Fall back on Mac Roman. */
760 string
= CFStringCreateWithBytes (NULL
, SDATA (s
), SBYTES (s
),
761 kCFStringEncodingMacRoman
, false);
767 /* From CFData to a lisp string. Always returns a unibyte string. */
770 cfdata_to_lisp (data
)
773 CFIndex len
= CFDataGetLength (data
);
774 Lisp_Object result
= make_uninit_string (len
);
776 CFDataGetBytes (data
, CFRangeMake (0, len
), SDATA (result
));
782 /* From CFString to a lisp string. Returns a unibyte string
783 containing a UTF-8 byte sequence. */
786 cfstring_to_lisp_nodecode (string
)
789 Lisp_Object result
= Qnil
;
790 const char *s
= CFStringGetCStringPtr (string
, kCFStringEncodingUTF8
);
793 result
= make_unibyte_string (s
, strlen (s
));
797 CFStringCreateExternalRepresentation (NULL
, string
,
798 kCFStringEncodingUTF8
, '?');
802 result
= cfdata_to_lisp (data
);
811 /* From CFString to a lisp string. Never returns a unibyte string
812 (even if it only contains ASCII characters).
813 This may cause GC during code conversion. */
816 cfstring_to_lisp (string
)
819 Lisp_Object result
= cfstring_to_lisp_nodecode (string
);
823 result
= code_convert_string_norecord (result
, Qutf_8
, 0);
824 /* This may be superfluous. Just to make sure that the result
825 is a multibyte string. */
826 result
= string_to_multibyte (result
);
833 /* CFNumber to a lisp integer or a lisp float. */
836 cfnumber_to_lisp (number
)
839 Lisp_Object result
= Qnil
;
840 #if BITS_PER_EMACS_INT > 32
842 CFNumberType emacs_int_type
= kCFNumberSInt64Type
;
845 CFNumberType emacs_int_type
= kCFNumberSInt32Type
;
849 if (CFNumberGetValue (number
, emacs_int_type
, &int_val
)
850 && !FIXNUM_OVERFLOW_P (int_val
))
851 result
= make_number (int_val
);
853 if (CFNumberGetValue (number
, kCFNumberDoubleType
, &float_val
))
854 result
= make_float (float_val
);
859 /* CFDate to a list of three integers as in a return value of
863 cfdate_to_lisp (date
)
866 static const CFGregorianDate epoch_gdate
= {1970, 1, 1, 0, 0, 0.0};
867 static CFAbsoluteTime epoch
= 0.0, sec
;
871 epoch
= CFGregorianDateGetAbsoluteTime (epoch_gdate
, NULL
);
873 sec
= CFDateGetAbsoluteTime (date
) - epoch
;
874 high
= sec
/ 65536.0;
875 low
= sec
- high
* 65536.0;
877 return list3 (make_number (high
), make_number (low
), make_number (0));
881 /* CFBoolean to a lisp symbol, `t' or `nil'. */
884 cfboolean_to_lisp (boolean
)
885 CFBooleanRef boolean
;
887 return CFBooleanGetValue (boolean
) ? Qt
: Qnil
;
891 /* Any Core Foundation object to a (lengthy) lisp string. */
894 cfobject_desc_to_lisp (object
)
897 Lisp_Object result
= Qnil
;
898 CFStringRef desc
= CFCopyDescription (object
);
902 result
= cfstring_to_lisp (desc
);
910 /* Callback functions for cfproperty_list_to_lisp. */
913 cfdictionary_add_to_list (key
, value
, context
)
918 struct cfdict_context
*cxt
= (struct cfdict_context
*)context
;
921 Fcons (Fcons (cfstring_to_lisp (key
),
922 cfproperty_list_to_lisp (value
, cxt
->with_tag
,
928 cfdictionary_puthash (key
, value
, context
)
933 Lisp_Object lisp_key
= cfstring_to_lisp (key
);
934 struct cfdict_context
*cxt
= (struct cfdict_context
*)context
;
935 struct Lisp_Hash_Table
*h
= XHASH_TABLE (*(cxt
->result
));
938 hash_lookup (h
, lisp_key
, &hash_code
);
939 hash_put (h
, lisp_key
,
940 cfproperty_list_to_lisp (value
, cxt
->with_tag
, cxt
->hash_bound
),
945 /* Convert CFPropertyList PLIST to a lisp object. If WITH_TAG is
946 non-zero, a symbol that represents the type of the original Core
947 Foundation object is prepended. HASH_BOUND specifies which kinds
948 of the lisp objects, alists or hash tables, are used as the targets
949 of the conversion from CFDictionary. If HASH_BOUND is negative,
950 always generate alists. If HASH_BOUND >= 0, generate an alist if
951 the number of keys in the dictionary is smaller than HASH_BOUND,
952 and a hash table otherwise. */
955 cfproperty_list_to_lisp (plist
, with_tag
, hash_bound
)
956 CFPropertyListRef plist
;
957 int with_tag
, hash_bound
;
959 CFTypeID type_id
= CFGetTypeID (plist
);
960 Lisp_Object tag
= Qnil
, result
= Qnil
;
961 struct gcpro gcpro1
, gcpro2
;
963 GCPRO2 (tag
, result
);
965 if (type_id
== CFStringGetTypeID ())
968 result
= cfstring_to_lisp (plist
);
970 else if (type_id
== CFNumberGetTypeID ())
973 result
= cfnumber_to_lisp (plist
);
975 else if (type_id
== CFBooleanGetTypeID ())
978 result
= cfboolean_to_lisp (plist
);
980 else if (type_id
== CFDateGetTypeID ())
983 result
= cfdate_to_lisp (plist
);
985 else if (type_id
== CFDataGetTypeID ())
988 result
= cfdata_to_lisp (plist
);
990 else if (type_id
== CFArrayGetTypeID ())
992 CFIndex index
, count
= CFArrayGetCount (plist
);
995 result
= Fmake_vector (make_number (count
), Qnil
);
996 for (index
= 0; index
< count
; index
++)
997 XVECTOR (result
)->contents
[index
] =
998 cfproperty_list_to_lisp (CFArrayGetValueAtIndex (plist
, index
),
999 with_tag
, hash_bound
);
1001 else if (type_id
== CFDictionaryGetTypeID ())
1003 struct cfdict_context context
;
1004 CFIndex count
= CFDictionaryGetCount (plist
);
1007 context
.result
= &result
;
1008 context
.with_tag
= with_tag
;
1009 context
.hash_bound
= hash_bound
;
1010 if (hash_bound
< 0 || count
< hash_bound
)
1013 CFDictionaryApplyFunction (plist
, cfdictionary_add_to_list
,
1018 result
= make_hash_table (Qequal
,
1019 make_number (count
),
1020 make_float (DEFAULT_REHASH_SIZE
),
1021 make_float (DEFAULT_REHASH_THRESHOLD
),
1023 CFDictionaryApplyFunction (plist
, cfdictionary_puthash
,
1033 result
= Fcons (tag
, result
);
1040 /***********************************************************************
1041 Emulation of the X Resource Manager
1042 ***********************************************************************/
1044 /* Parser functions for resource lines. Each function takes an
1045 address of a variable whose value points to the head of a string.
1046 The value will be advanced so that it points to the next character
1047 of the parsed part when the function returns.
1049 A resource name such as "Emacs*font" is parsed into a non-empty
1050 list called `quarks'. Each element is either a Lisp string that
1051 represents a concrete component, a Lisp symbol LOOSE_BINDING
1052 (actually Qlambda) that represents any number (>=0) of intervening
1053 components, or a Lisp symbol SINGLE_COMPONENT (actually Qquote)
1054 that represents as any single component. */
1058 #define LOOSE_BINDING Qlambda /* '*' ("L"oose) */
1059 #define SINGLE_COMPONENT Qquote /* '?' ("Q"uestion) */
1062 skip_white_space (p
)
1065 /* WhiteSpace = {<space> | <horizontal tab>} */
1066 while (*P
== ' ' || *P
== '\t')
1074 /* Comment = "!" {<any character except null or newline>} */
1087 /* Don't interpret filename. Just skip until the newline. */
1089 parse_include_file (p
)
1092 /* IncludeFile = "#" WhiteSpace "include" WhiteSpace FileName WhiteSpace */
1109 /* Binding = "." | "*" */
1110 if (*P
== '.' || *P
== '*')
1112 char binding
= *P
++;
1114 while (*P
== '.' || *P
== '*')
1127 /* Component = "?" | ComponentName
1128 ComponentName = NameChar {NameChar}
1129 NameChar = "a"-"z" | "A"-"Z" | "0"-"9" | "_" | "-" */
1133 return SINGLE_COMPONENT
;
1135 else if (isalnum (*P
) || *P
== '_' || *P
== '-')
1139 while (isalnum (*P
) || *P
== '_' || *P
== '-')
1142 return make_unibyte_string (start
, P
- start
);
1149 parse_resource_name (p
)
1152 Lisp_Object result
= Qnil
, component
;
1155 /* ResourceName = [Binding] {Component Binding} ComponentName */
1156 if (parse_binding (p
) == '*')
1157 result
= Fcons (LOOSE_BINDING
, result
);
1159 component
= parse_component (p
);
1160 if (NILP (component
))
1163 result
= Fcons (component
, result
);
1164 while ((binding
= parse_binding (p
)) != '\0')
1167 result
= Fcons (LOOSE_BINDING
, result
);
1168 component
= parse_component (p
);
1169 if (NILP (component
))
1172 result
= Fcons (component
, result
);
1175 /* The final component should not be '?'. */
1176 if (EQ (component
, SINGLE_COMPONENT
))
1179 return Fnreverse (result
);
1187 Lisp_Object seq
= Qnil
, result
;
1188 int buf_len
, total_len
= 0, len
, continue_p
;
1190 q
= strchr (P
, '\n');
1191 buf_len
= q
? q
- P
: strlen (P
);
1192 buf
= xmalloc (buf_len
);
1205 else if (*P
== '\\')
1210 else if (*P
== '\n')
1221 else if ('0' <= P
[0] && P
[0] <= '7'
1222 && '0' <= P
[1] && P
[1] <= '7'
1223 && '0' <= P
[2] && P
[2] <= '7')
1225 *q
++ = (P
[0] - '0' << 6) + (P
[1] - '0' << 3) + (P
[2] - '0');
1235 seq
= Fcons (make_unibyte_string (buf
, len
), seq
);
1240 q
= strchr (P
, '\n');
1241 len
= q
? q
- P
: strlen (P
);
1246 buf
= xmalloc (buf_len
);
1254 if (SBYTES (XCAR (seq
)) == total_len
)
1255 return make_string (SDATA (XCAR (seq
)), total_len
);
1258 buf
= xmalloc (total_len
);
1259 q
= buf
+ total_len
;
1260 for (; CONSP (seq
); seq
= XCDR (seq
))
1262 len
= SBYTES (XCAR (seq
));
1264 memcpy (q
, SDATA (XCAR (seq
)), len
);
1266 result
= make_string (buf
, total_len
);
1273 parse_resource_line (p
)
1276 Lisp_Object quarks
, value
;
1278 /* ResourceLine = Comment | IncludeFile | ResourceSpec | <empty line> */
1279 if (parse_comment (p
) || parse_include_file (p
))
1282 /* ResourceSpec = WhiteSpace ResourceName WhiteSpace ":" WhiteSpace Value */
1283 skip_white_space (p
);
1284 quarks
= parse_resource_name (p
);
1287 skip_white_space (p
);
1291 skip_white_space (p
);
1292 value
= parse_value (p
);
1293 return Fcons (quarks
, value
);
1296 /* Skip the remaining data as a dummy value. */
1303 /* Equivalents of X Resource Manager functions.
1305 An X Resource Database acts as a collection of resource names and
1306 associated values. It is implemented as a trie on quarks. Namely,
1307 each edge is labeled by either a string, LOOSE_BINDING, or
1308 SINGLE_COMPONENT. Each node has a node id, which is a unique
1309 nonnegative integer, and the root node id is 0. A database is
1310 implemented as a hash table that maps a pair (SRC-NODE-ID .
1311 EDGE-LABEL) to DEST-NODE-ID. It also holds a maximum node id used
1312 in the table as a value for HASHKEY_MAX_NID. A value associated to
1313 a node is recorded as a value for the node id.
1315 A database also has a cache for past queries as a value for
1316 HASHKEY_QUERY_CACHE. It is another hash table that maps
1317 "NAME-STRING\0CLASS-STRING" to the result of the query. */
1319 #define HASHKEY_MAX_NID (make_number (0))
1320 #define HASHKEY_QUERY_CACHE (make_number (-1))
1323 xrm_create_database ()
1325 XrmDatabase database
;
1327 database
= make_hash_table (Qequal
, make_number (DEFAULT_HASH_SIZE
),
1328 make_float (DEFAULT_REHASH_SIZE
),
1329 make_float (DEFAULT_REHASH_THRESHOLD
),
1331 Fputhash (HASHKEY_MAX_NID
, make_number (0), database
);
1332 Fputhash (HASHKEY_QUERY_CACHE
, Qnil
, database
);
1338 xrm_q_put_resource (database
, quarks
, value
)
1339 XrmDatabase database
;
1340 Lisp_Object quarks
, value
;
1342 struct Lisp_Hash_Table
*h
= XHASH_TABLE (database
);
1345 Lisp_Object node_id
, key
;
1347 max_nid
= XINT (Fgethash (HASHKEY_MAX_NID
, database
, Qnil
));
1349 XSETINT (node_id
, 0);
1350 for (; CONSP (quarks
); quarks
= XCDR (quarks
))
1352 key
= Fcons (node_id
, XCAR (quarks
));
1353 i
= hash_lookup (h
, key
, &hash_code
);
1357 XSETINT (node_id
, max_nid
);
1358 hash_put (h
, key
, node_id
, hash_code
);
1361 node_id
= HASH_VALUE (h
, i
);
1363 Fputhash (node_id
, value
, database
);
1365 Fputhash (HASHKEY_MAX_NID
, make_number (max_nid
), database
);
1366 Fputhash (HASHKEY_QUERY_CACHE
, Qnil
, database
);
1369 /* Merge multiple resource entries specified by DATA into a resource
1370 database DATABASE. DATA points to the head of a null-terminated
1371 string consisting of multiple resource lines. It's like a
1372 combination of XrmGetStringDatabase and XrmMergeDatabases. */
1375 xrm_merge_string_database (database
, data
)
1376 XrmDatabase database
;
1379 Lisp_Object quarks_value
;
1383 quarks_value
= parse_resource_line (&data
);
1384 if (!NILP (quarks_value
))
1385 xrm_q_put_resource (database
,
1386 XCAR (quarks_value
), XCDR (quarks_value
));
1391 xrm_q_get_resource_1 (database
, node_id
, quark_name
, quark_class
)
1392 XrmDatabase database
;
1393 Lisp_Object node_id
, quark_name
, quark_class
;
1395 struct Lisp_Hash_Table
*h
= XHASH_TABLE (database
);
1396 Lisp_Object key
, labels
[3], value
;
1399 if (!CONSP (quark_name
))
1400 return Fgethash (node_id
, database
, Qnil
);
1402 /* First, try tight bindings */
1403 labels
[0] = XCAR (quark_name
);
1404 labels
[1] = XCAR (quark_class
);
1405 labels
[2] = SINGLE_COMPONENT
;
1407 key
= Fcons (node_id
, Qnil
);
1408 for (k
= 0; k
< sizeof (labels
) / sizeof (*labels
); k
++)
1410 XSETCDR (key
, labels
[k
]);
1411 i
= hash_lookup (h
, key
, NULL
);
1414 value
= xrm_q_get_resource_1 (database
, HASH_VALUE (h
, i
),
1415 XCDR (quark_name
), XCDR (quark_class
));
1421 /* Then, try loose bindings */
1422 XSETCDR (key
, LOOSE_BINDING
);
1423 i
= hash_lookup (h
, key
, NULL
);
1426 value
= xrm_q_get_resource_1 (database
, HASH_VALUE (h
, i
),
1427 quark_name
, quark_class
);
1431 return xrm_q_get_resource_1 (database
, node_id
,
1432 XCDR (quark_name
), XCDR (quark_class
));
1439 xrm_q_get_resource (database
, quark_name
, quark_class
)
1440 XrmDatabase database
;
1441 Lisp_Object quark_name
, quark_class
;
1443 return xrm_q_get_resource_1 (database
, make_number (0),
1444 quark_name
, quark_class
);
1447 /* Retrieve a resource value for the specified NAME and CLASS from the
1448 resource database DATABASE. It corresponds to XrmGetResource. */
1451 xrm_get_resource (database
, name
, class)
1452 XrmDatabase database
;
1455 Lisp_Object key
, query_cache
, quark_name
, quark_class
, tmp
;
1457 struct Lisp_Hash_Table
*h
;
1461 nc
= strlen (class);
1462 key
= make_uninit_string (nn
+ nc
+ 1);
1463 strcpy (SDATA (key
), name
);
1464 strncpy (SDATA (key
) + nn
+ 1, class, nc
);
1466 query_cache
= Fgethash (HASHKEY_QUERY_CACHE
, database
, Qnil
);
1467 if (NILP (query_cache
))
1469 query_cache
= make_hash_table (Qequal
, make_number (DEFAULT_HASH_SIZE
),
1470 make_float (DEFAULT_REHASH_SIZE
),
1471 make_float (DEFAULT_REHASH_THRESHOLD
),
1473 Fputhash (HASHKEY_QUERY_CACHE
, query_cache
, database
);
1475 h
= XHASH_TABLE (query_cache
);
1476 i
= hash_lookup (h
, key
, &hash_code
);
1478 return HASH_VALUE (h
, i
);
1480 quark_name
= parse_resource_name (&name
);
1483 for (tmp
= quark_name
, nn
= 0; CONSP (tmp
); tmp
= XCDR (tmp
), nn
++)
1484 if (!STRINGP (XCAR (tmp
)))
1487 quark_class
= parse_resource_name (&class);
1490 for (tmp
= quark_class
, nc
= 0; CONSP (tmp
); tmp
= XCDR (tmp
), nc
++)
1491 if (!STRINGP (XCAR (tmp
)))
1498 tmp
= xrm_q_get_resource (database
, quark_name
, quark_class
);
1499 hash_put (h
, key
, tmp
, hash_code
);
1504 #if TARGET_API_MAC_CARBON
1506 xrm_cfproperty_list_to_value (plist
)
1507 CFPropertyListRef plist
;
1509 CFTypeID type_id
= CFGetTypeID (plist
);
1511 if (type_id
== CFStringGetTypeID ())
1512 return cfstring_to_lisp (plist
);
1513 else if (type_id
== CFNumberGetTypeID ())
1516 Lisp_Object result
= Qnil
;
1518 string
= CFStringCreateWithFormat (NULL
, NULL
, CFSTR ("%@"), plist
);
1521 result
= cfstring_to_lisp (string
);
1526 else if (type_id
== CFBooleanGetTypeID ())
1527 return build_string (CFBooleanGetValue (plist
) ? "true" : "false");
1528 else if (type_id
== CFDataGetTypeID ())
1529 return cfdata_to_lisp (plist
);
1535 /* Create a new resource database from the preferences for the
1536 application APPLICATION. APPLICATION is either a string that
1537 specifies an application ID, or NULL that represents the current
1541 xrm_get_preference_database (application
)
1544 #if TARGET_API_MAC_CARBON
1545 CFStringRef app_id
, *keys
, user_doms
[2], host_doms
[2];
1546 CFMutableSetRef key_set
= NULL
;
1547 CFArrayRef key_array
;
1548 CFIndex index
, count
;
1550 XrmDatabase database
;
1551 Lisp_Object quarks
= Qnil
, value
= Qnil
;
1552 CFPropertyListRef plist
;
1554 struct gcpro gcpro1
, gcpro2
, gcpro3
;
1556 user_doms
[0] = kCFPreferencesCurrentUser
;
1557 user_doms
[1] = kCFPreferencesAnyUser
;
1558 host_doms
[0] = kCFPreferencesCurrentHost
;
1559 host_doms
[1] = kCFPreferencesAnyHost
;
1561 database
= xrm_create_database ();
1563 GCPRO3 (database
, quarks
, value
);
1567 app_id
= kCFPreferencesCurrentApplication
;
1570 app_id
= cfstring_create_with_utf8_cstring (application
);
1575 key_set
= CFSetCreateMutable (NULL
, 0, &kCFCopyStringSetCallBacks
);
1576 if (key_set
== NULL
)
1578 for (iu
= 0; iu
< sizeof (user_doms
) / sizeof (*user_doms
) ; iu
++)
1579 for (ih
= 0; ih
< sizeof (host_doms
) / sizeof (*host_doms
); ih
++)
1581 key_array
= CFPreferencesCopyKeyList (app_id
, user_doms
[iu
],
1585 count
= CFArrayGetCount (key_array
);
1586 for (index
= 0; index
< count
; index
++)
1587 CFSetAddValue (key_set
,
1588 CFArrayGetValueAtIndex (key_array
, index
));
1589 CFRelease (key_array
);
1593 count
= CFSetGetCount (key_set
);
1594 keys
= xmalloc (sizeof (CFStringRef
) * count
);
1597 CFSetGetValues (key_set
, (const void **)keys
);
1598 for (index
= 0; index
< count
; index
++)
1600 res_name
= SDATA (cfstring_to_lisp_nodecode (keys
[index
]));
1601 quarks
= parse_resource_name (&res_name
);
1602 if (!(NILP (quarks
) || *res_name
))
1604 plist
= CFPreferencesCopyAppValue (keys
[index
], app_id
);
1605 value
= xrm_cfproperty_list_to_value (plist
);
1608 xrm_q_put_resource (database
, quarks
, value
);
1615 CFRelease (key_set
);
1624 return xrm_create_database ();
1631 /* The following functions with "sys_" prefix are stubs to Unix
1632 functions that have already been implemented by CW or MPW. The
1633 calls to them in Emacs source course are #define'd to call the sys_
1634 versions by the header files s-mac.h. In these stubs pathnames are
1635 converted between their Unix and Mac forms. */
1638 /* Unix epoch is Jan 1, 1970 while Mac epoch is Jan 1, 1904: 66 years
1639 + 17 leap days. These are for adjusting time values returned by
1640 MacOS Toolbox functions. */
1642 #define MAC_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
1645 #if __MSL__ < 0x6000
1646 /* CW Pro 5 epoch is Jan 1, 1900 (aaarghhhhh!); remember, 1900 is not
1647 a leap year! This is for adjusting time_t values returned by MSL
1649 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 70 + 17) * 24 * 60 * 60)
1650 #else /* __MSL__ >= 0x6000 */
1651 /* CW changes Pro 6 to follow Unix! */
1652 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
1653 #endif /* __MSL__ >= 0x6000 */
1655 /* MPW library functions follow Unix (confused?). */
1656 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
1657 #else /* not __MRC__ */
1659 #endif /* not __MRC__ */
1662 /* Define our own stat function for both MrC and CW. The reason for
1663 doing this: "stat" is both the name of a struct and function name:
1664 can't use the same trick like that for sys_open, sys_close, etc. to
1665 redirect Emacs's calls to our own version that converts Unix style
1666 filenames to Mac style filename because all sorts of compilation
1667 errors will be generated if stat is #define'd to be sys_stat. */
1670 stat_noalias (const char *path
, struct stat
*buf
)
1672 char mac_pathname
[MAXPATHLEN
+1];
1675 if (posix_to_mac_pathname (path
, mac_pathname
, MAXPATHLEN
+1) == 0)
1678 c2pstr (mac_pathname
);
1679 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
1680 cipb
.hFileInfo
.ioVRefNum
= 0;
1681 cipb
.hFileInfo
.ioDirID
= 0;
1682 cipb
.hFileInfo
.ioFDirIndex
= 0;
1683 /* set to 0 to get information about specific dir or file */
1685 errno
= PBGetCatInfo (&cipb
, false);
1686 if (errno
== -43) /* -43: fnfErr defined in Errors.h */
1691 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* bit 4 = 1 for directories */
1693 buf
->st_mode
= S_IFDIR
| S_IREAD
| S_IEXEC
;
1695 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x1))
1696 buf
->st_mode
|= S_IWRITE
; /* bit 1 = 1 for locked files/directories */
1697 buf
->st_ino
= cipb
.dirInfo
.ioDrDirID
;
1698 buf
->st_dev
= cipb
.dirInfo
.ioVRefNum
;
1699 buf
->st_size
= cipb
.dirInfo
.ioDrNmFls
;
1700 /* size of dir = number of files and dirs */
1703 = cipb
.dirInfo
.ioDrMdDat
- MAC_UNIX_EPOCH_DIFF
;
1704 buf
->st_ctime
= cipb
.dirInfo
.ioDrCrDat
- MAC_UNIX_EPOCH_DIFF
;
1708 buf
->st_mode
= S_IFREG
| S_IREAD
;
1709 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x1))
1710 buf
->st_mode
|= S_IWRITE
; /* bit 1 = 1 for locked files/directories */
1711 if (cipb
.hFileInfo
.ioFlFndrInfo
.fdType
== 'APPL')
1712 buf
->st_mode
|= S_IEXEC
;
1713 buf
->st_ino
= cipb
.hFileInfo
.ioDirID
;
1714 buf
->st_dev
= cipb
.hFileInfo
.ioVRefNum
;
1715 buf
->st_size
= cipb
.hFileInfo
.ioFlLgLen
;
1718 = cipb
.hFileInfo
.ioFlMdDat
- MAC_UNIX_EPOCH_DIFF
;
1719 buf
->st_ctime
= cipb
.hFileInfo
.ioFlCrDat
- MAC_UNIX_EPOCH_DIFF
;
1722 if (cipb
.hFileInfo
.ioFlFndrInfo
.fdFlags
& 0x8000)
1724 /* identify alias files as symlinks */
1725 buf
->st_mode
&= ~S_IFREG
;
1726 buf
->st_mode
|= S_IFLNK
;
1730 buf
->st_uid
= getuid ();
1731 buf
->st_gid
= getgid ();
1739 lstat (const char *path
, struct stat
*buf
)
1742 char true_pathname
[MAXPATHLEN
+1];
1744 /* Try looking for the file without resolving aliases first. */
1745 if ((result
= stat_noalias (path
, buf
)) >= 0)
1748 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
1751 return stat_noalias (true_pathname
, buf
);
1756 stat (const char *path
, struct stat
*sb
)
1759 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
1762 if ((result
= stat_noalias (path
, sb
)) >= 0 &&
1763 ! (sb
->st_mode
& S_IFLNK
))
1766 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
1769 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
1772 fully_resolved_name
[len
] = '\0';
1773 /* in fact our readlink terminates strings */
1774 return lstat (fully_resolved_name
, sb
);
1777 return lstat (true_pathname
, sb
);
1782 /* CW defines fstat in stat.mac.c while MPW does not provide this
1783 function. Without the information of how to get from a file
1784 descriptor in MPW StdCLib to a Mac OS file spec, it should be hard
1785 to implement this function. Fortunately, there is only one place
1786 where this function is called in our configuration: in fileio.c,
1787 where only the st_dev and st_ino fields are used to determine
1788 whether two fildes point to different i-nodes to prevent copying
1789 a file onto itself equal. What we have here probably needs
1793 fstat (int fildes
, struct stat
*buf
)
1796 buf
->st_ino
= fildes
;
1797 buf
->st_mode
= S_IFREG
; /* added by T.I. for the copy-file */
1798 return 0; /* success */
1800 #endif /* __MRC__ */
1804 mkdir (const char *dirname
, int mode
)
1806 #pragma unused(mode)
1809 char true_pathname
[MAXPATHLEN
+1], mac_pathname
[MAXPATHLEN
+1];
1811 if (find_true_pathname (dirname
, true_pathname
, MAXPATHLEN
+1) == -1)
1814 if (posix_to_mac_pathname (true_pathname
, mac_pathname
, MAXPATHLEN
+1) == 0)
1817 c2pstr (mac_pathname
);
1818 hfpb
.ioNamePtr
= mac_pathname
;
1819 hfpb
.ioVRefNum
= 0; /* ignored unless name is invalid */
1820 hfpb
.ioDirID
= 0; /* parent is the root */
1822 errno
= PBDirCreate ((HParmBlkPtr
) &hfpb
, false);
1823 /* just return the Mac OSErr code for now */
1824 return errno
== noErr
? 0 : -1;
1829 sys_rmdir (const char *dirname
)
1832 char mac_pathname
[MAXPATHLEN
+1];
1834 if (posix_to_mac_pathname (dirname
, mac_pathname
, MAXPATHLEN
+1) == 0)
1837 c2pstr (mac_pathname
);
1838 hfpb
.ioNamePtr
= mac_pathname
;
1839 hfpb
.ioVRefNum
= 0; /* ignored unless name is invalid */
1840 hfpb
.ioDirID
= 0; /* parent is the root */
1842 errno
= PBHDelete ((HParmBlkPtr
) &hfpb
, false);
1843 return errno
== noErr
? 0 : -1;
1848 /* No implementation yet. */
1850 execvp (const char *path
, ...)
1854 #endif /* __MRC__ */
1858 utime (const char *path
, const struct utimbuf
*times
)
1860 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
1862 char mac_pathname
[MAXPATHLEN
+1];
1865 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
1868 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
1870 fully_resolved_name
[len
] = '\0';
1872 strcpy (fully_resolved_name
, true_pathname
);
1874 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
1877 c2pstr (mac_pathname
);
1878 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
1879 cipb
.hFileInfo
.ioVRefNum
= 0;
1880 cipb
.hFileInfo
.ioDirID
= 0;
1881 cipb
.hFileInfo
.ioFDirIndex
= 0;
1882 /* set to 0 to get information about specific dir or file */
1884 errno
= PBGetCatInfo (&cipb
, false);
1888 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* bit 4 = 1 for directories */
1891 cipb
.dirInfo
.ioDrMdDat
= times
->modtime
+ MAC_UNIX_EPOCH_DIFF
;
1893 GetDateTime (&cipb
.dirInfo
.ioDrMdDat
);
1898 cipb
.hFileInfo
.ioFlMdDat
= times
->modtime
+ MAC_UNIX_EPOCH_DIFF
;
1900 GetDateTime (&cipb
.hFileInfo
.ioFlMdDat
);
1903 errno
= PBSetCatInfo (&cipb
, false);
1904 return errno
== noErr
? 0 : -1;
1918 /* Like stat, but test for access mode in hfpb.ioFlAttrib */
1920 access (const char *path
, int mode
)
1922 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
1924 char mac_pathname
[MAXPATHLEN
+1];
1927 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
1930 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
1932 fully_resolved_name
[len
] = '\0';
1934 strcpy (fully_resolved_name
, true_pathname
);
1936 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
1939 c2pstr (mac_pathname
);
1940 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
1941 cipb
.hFileInfo
.ioVRefNum
= 0;
1942 cipb
.hFileInfo
.ioDirID
= 0;
1943 cipb
.hFileInfo
.ioFDirIndex
= 0;
1944 /* set to 0 to get information about specific dir or file */
1946 errno
= PBGetCatInfo (&cipb
, false);
1950 if (mode
== F_OK
) /* got this far, file exists */
1954 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* path refers to a directory */
1958 if (cipb
.hFileInfo
.ioFlFndrInfo
.fdType
== 'APPL')
1965 return (cipb
.hFileInfo
.ioFlAttrib
& 0x1) ? -1 : 0;
1966 /* don't allow if lock bit is on */
1972 #define DEV_NULL_FD 0x10000
1976 sys_open (const char *path
, int oflag
)
1978 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
1980 char mac_pathname
[MAXPATHLEN
+1];
1982 if (strcmp (path
, "/dev/null") == 0)
1983 return DEV_NULL_FD
; /* some bogus fd to be ignored in write */
1985 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
1988 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
1990 fully_resolved_name
[len
] = '\0';
1992 strcpy (fully_resolved_name
, true_pathname
);
1994 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
1999 int res
= open (mac_pathname
, oflag
);
2000 /* if (oflag == O_WRONLY || oflag == O_RDWR) */
2001 if (oflag
& O_CREAT
)
2002 fsetfileinfo (mac_pathname
, 'EMAx', 'TEXT');
2004 #else /* not __MRC__ */
2005 return open (mac_pathname
, oflag
);
2006 #endif /* not __MRC__ */
2013 sys_creat (const char *path
, mode_t mode
)
2015 char true_pathname
[MAXPATHLEN
+1];
2017 char mac_pathname
[MAXPATHLEN
+1];
2019 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
2022 if (!posix_to_mac_pathname (true_pathname
, mac_pathname
, MAXPATHLEN
+1))
2027 int result
= creat (mac_pathname
);
2028 fsetfileinfo (mac_pathname
, 'EMAx', 'TEXT');
2030 #else /* not __MRC__ */
2031 return creat (mac_pathname
, mode
);
2032 #endif /* not __MRC__ */
2039 sys_unlink (const char *path
)
2041 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
2043 char mac_pathname
[MAXPATHLEN
+1];
2045 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
2048 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
2050 fully_resolved_name
[len
] = '\0';
2052 strcpy (fully_resolved_name
, true_pathname
);
2054 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
2057 return unlink (mac_pathname
);
2063 sys_read (int fildes
, char *buf
, int count
)
2065 if (fildes
== 0) /* this should not be used for console input */
2068 #if __MSL__ >= 0x6000
2069 return _read (fildes
, buf
, count
);
2071 return read (fildes
, buf
, count
);
2078 sys_write (int fildes
, const char *buf
, int count
)
2080 if (fildes
== DEV_NULL_FD
)
2083 #if __MSL__ >= 0x6000
2084 return _write (fildes
, buf
, count
);
2086 return write (fildes
, buf
, count
);
2093 sys_rename (const char * old_name
, const char * new_name
)
2095 char true_old_pathname
[MAXPATHLEN
+1], true_new_pathname
[MAXPATHLEN
+1];
2096 char fully_resolved_old_name
[MAXPATHLEN
+1];
2098 char mac_old_name
[MAXPATHLEN
+1], mac_new_name
[MAXPATHLEN
+1];
2100 if (find_true_pathname (old_name
, true_old_pathname
, MAXPATHLEN
+1) == -1)
2103 len
= readlink (true_old_pathname
, fully_resolved_old_name
, MAXPATHLEN
);
2105 fully_resolved_old_name
[len
] = '\0';
2107 strcpy (fully_resolved_old_name
, true_old_pathname
);
2109 if (find_true_pathname (new_name
, true_new_pathname
, MAXPATHLEN
+1) == -1)
2112 if (strcmp (fully_resolved_old_name
, true_new_pathname
) == 0)
2115 if (!posix_to_mac_pathname (fully_resolved_old_name
,
2120 if (!posix_to_mac_pathname(true_new_pathname
, mac_new_name
, MAXPATHLEN
+1))
2123 /* If a file with new_name already exists, rename deletes the old
2124 file in Unix. CW version fails in these situation. So we add a
2125 call to unlink here. */
2126 (void) unlink (mac_new_name
);
2128 return rename (mac_old_name
, mac_new_name
);
2133 extern FILE *fopen (const char *name
, const char *mode
);
2135 sys_fopen (const char *name
, const char *mode
)
2137 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
2139 char mac_pathname
[MAXPATHLEN
+1];
2141 if (find_true_pathname (name
, true_pathname
, MAXPATHLEN
+1) == -1)
2144 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
2146 fully_resolved_name
[len
] = '\0';
2148 strcpy (fully_resolved_name
, true_pathname
);
2150 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
2155 if (mode
[0] == 'w' || mode
[0] == 'a')
2156 fsetfileinfo (mac_pathname
, 'EMAx', 'TEXT');
2157 #endif /* not __MRC__ */
2158 return fopen (mac_pathname
, mode
);
2163 #include "keyboard.h"
2164 extern Boolean
mac_wait_next_event (EventRecord
*, UInt32
, Boolean
);
2167 select (n
, rfds
, wfds
, efds
, timeout
)
2172 struct timeval
*timeout
;
2175 #if TARGET_API_MAC_CARBON
2176 EventTimeout timeout_sec
=
2178 ? (EMACS_SECS (*timeout
) * kEventDurationSecond
2179 + EMACS_USECS (*timeout
) * kEventDurationMicrosecond
)
2180 : kEventDurationForever
);
2183 err
= ReceiveNextEvent (0, NULL
, timeout_sec
, kEventLeaveInQueue
, NULL
);
2185 #else /* not TARGET_API_MAC_CARBON */
2187 UInt32 sleep_time
= EMACS_SECS (*timeout
) * 60 +
2188 ((EMACS_USECS (*timeout
) * 60) / 1000000);
2190 /* Can only handle wait for keyboard input. */
2191 if (n
> 1 || wfds
|| efds
)
2194 /* Also return true if an event other than a keyDown has occurred.
2195 This causes kbd_buffer_get_event in keyboard.c to call
2196 read_avail_input which in turn calls XTread_socket to poll for
2197 these events. Otherwise these never get processed except but a
2198 very slow poll timer. */
2199 if (mac_wait_next_event (&e
, sleep_time
, false))
2202 err
= -9875; /* eventLoopTimedOutErr */
2203 #endif /* not TARGET_API_MAC_CARBON */
2205 if (FD_ISSET (0, rfds
))
2216 if (input_polling_used ())
2218 /* It could be confusing if a real alarm arrives while
2219 processing the fake one. Turn it off and let the
2220 handler reset it. */
2221 extern void poll_for_input_1
P_ ((void));
2222 int old_poll_suppress_count
= poll_suppress_count
;
2223 poll_suppress_count
= 1;
2224 poll_for_input_1 ();
2225 poll_suppress_count
= old_poll_suppress_count
;
2235 /* Simulation of SIGALRM. The stub for function signal stores the
2236 signal handler function in alarm_signal_func if a SIGALRM is
2240 #include "syssignal.h"
2242 static TMTask mac_atimer_task
;
2244 static QElemPtr mac_atimer_qlink
= (QElemPtr
) &mac_atimer_task
;
2246 static int signal_mask
= 0;
2249 __sigfun alarm_signal_func
= (__sigfun
) 0;
2251 __signal_func_ptr alarm_signal_func
= (__signal_func_ptr
) 0;
2252 #else /* not __MRC__ and not __MWERKS__ */
2254 #endif /* not __MRC__ and not __MWERKS__ */
2258 extern __sigfun
signal (int signal
, __sigfun signal_func
);
2260 sys_signal (int signal_num
, __sigfun signal_func
)
2262 extern __signal_func_ptr
signal (int signal
, __signal_func_ptr signal_func
);
2264 sys_signal (int signal_num
, __signal_func_ptr signal_func
)
2265 #else /* not __MRC__ and not __MWERKS__ */
2267 #endif /* not __MRC__ and not __MWERKS__ */
2269 if (signal_num
!= SIGALRM
)
2270 return signal (signal_num
, signal_func
);
2274 __sigfun old_signal_func
;
2276 __signal_func_ptr old_signal_func
;
2280 old_signal_func
= alarm_signal_func
;
2281 alarm_signal_func
= signal_func
;
2282 return old_signal_func
;
2288 mac_atimer_handler (qlink
)
2291 if (alarm_signal_func
)
2292 (alarm_signal_func
) (SIGALRM
);
2297 set_mac_atimer (count
)
2300 static TimerUPP mac_atimer_handlerUPP
= NULL
;
2302 if (mac_atimer_handlerUPP
== NULL
)
2303 mac_atimer_handlerUPP
= NewTimerUPP (mac_atimer_handler
);
2304 mac_atimer_task
.tmCount
= 0;
2305 mac_atimer_task
.tmAddr
= mac_atimer_handlerUPP
;
2306 mac_atimer_qlink
= (QElemPtr
) &mac_atimer_task
;
2307 InsTime (mac_atimer_qlink
);
2309 PrimeTime (mac_atimer_qlink
, count
);
2314 remove_mac_atimer (remaining_count
)
2315 long *remaining_count
;
2317 if (mac_atimer_qlink
)
2319 RmvTime (mac_atimer_qlink
);
2320 if (remaining_count
)
2321 *remaining_count
= mac_atimer_task
.tmCount
;
2322 mac_atimer_qlink
= NULL
;
2334 int old_mask
= signal_mask
;
2336 signal_mask
|= mask
;
2338 if ((old_mask
^ signal_mask
) & sigmask (SIGALRM
))
2339 remove_mac_atimer (NULL
);
2346 sigsetmask (int mask
)
2348 int old_mask
= signal_mask
;
2352 if ((old_mask
^ signal_mask
) & sigmask (SIGALRM
))
2353 if (signal_mask
& sigmask (SIGALRM
))
2354 remove_mac_atimer (NULL
);
2356 set_mac_atimer (mac_atimer_task
.tmCount
);
2365 long remaining_count
;
2367 if (remove_mac_atimer (&remaining_count
) == 0)
2369 set_mac_atimer (seconds
* 1000);
2371 return remaining_count
/ 1000;
2375 mac_atimer_task
.tmCount
= seconds
* 1000;
2383 setitimer (which
, value
, ovalue
)
2385 const struct itimerval
*value
;
2386 struct itimerval
*ovalue
;
2388 long remaining_count
;
2389 long count
= (EMACS_SECS (value
->it_value
) * 1000
2390 + (EMACS_USECS (value
->it_value
) + 999) / 1000);
2392 if (remove_mac_atimer (&remaining_count
) == 0)
2396 bzero (ovalue
, sizeof (*ovalue
));
2397 EMACS_SET_SECS_USECS (ovalue
->it_value
, remaining_count
/ 1000,
2398 (remaining_count
% 1000) * 1000);
2400 set_mac_atimer (count
);
2403 mac_atimer_task
.tmCount
= count
;
2409 /* gettimeofday should return the amount of time (in a timeval
2410 structure) since midnight today. The toolbox function Microseconds
2411 returns the number of microseconds (in a UnsignedWide value) since
2412 the machine was booted. Also making this complicated is WideAdd,
2413 WideSubtract, etc. take wide values. */
2420 static wide wall_clock_at_epoch
, clicks_at_epoch
;
2421 UnsignedWide uw_microseconds
;
2422 wide w_microseconds
;
2423 time_t sys_time (time_t *);
2425 /* If this function is called for the first time, record the number
2426 of seconds since midnight and the number of microseconds since
2427 boot at the time of this first call. */
2432 systime
= sys_time (NULL
);
2433 /* Store microseconds since midnight in wall_clock_at_epoch. */
2434 WideMultiply (systime
, 1000000L, &wall_clock_at_epoch
);
2435 Microseconds (&uw_microseconds
);
2436 /* Store microseconds since boot in clicks_at_epoch. */
2437 clicks_at_epoch
.hi
= uw_microseconds
.hi
;
2438 clicks_at_epoch
.lo
= uw_microseconds
.lo
;
2441 /* Get time since boot */
2442 Microseconds (&uw_microseconds
);
2444 /* Convert to time since midnight*/
2445 w_microseconds
.hi
= uw_microseconds
.hi
;
2446 w_microseconds
.lo
= uw_microseconds
.lo
;
2447 WideSubtract (&w_microseconds
, &clicks_at_epoch
);
2448 WideAdd (&w_microseconds
, &wall_clock_at_epoch
);
2449 tp
->tv_sec
= WideDivide (&w_microseconds
, 1000000L, &tp
->tv_usec
);
2457 sleep (unsigned int seconds
)
2459 unsigned long time_up
;
2462 time_up
= TickCount () + seconds
* 60;
2463 while (TickCount () < time_up
)
2465 /* Accept no event; just wait. by T.I. */
2466 WaitNextEvent (0, &e
, 30, NULL
);
2471 #endif /* __MRC__ */
2474 /* The time functions adjust time values according to the difference
2475 between the Unix and CW epoches. */
2478 extern struct tm
*gmtime (const time_t *);
2480 sys_gmtime (const time_t *timer
)
2482 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
2484 return gmtime (&unix_time
);
2489 extern struct tm
*localtime (const time_t *);
2491 sys_localtime (const time_t *timer
)
2493 #if __MSL__ >= 0x6000
2494 time_t unix_time
= *timer
;
2496 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
2499 return localtime (&unix_time
);
2504 extern char *ctime (const time_t *);
2506 sys_ctime (const time_t *timer
)
2508 #if __MSL__ >= 0x6000
2509 time_t unix_time
= *timer
;
2511 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
2514 return ctime (&unix_time
);
2519 extern time_t time (time_t *);
2521 sys_time (time_t *timer
)
2523 #if __MSL__ >= 0x6000
2524 time_t mac_time
= time (NULL
);
2526 time_t mac_time
= time (NULL
) - CW_OR_MPW_UNIX_EPOCH_DIFF
;
2536 /* no subprocesses, empty wait */
2546 croak (char *badfunc
)
2548 printf ("%s not yet implemented\r\n", badfunc
);
2554 mktemp (char *template)
2559 len
= strlen (template);
2561 while (k
>= 0 && template[k
] == 'X')
2564 k
++; /* make k index of first 'X' */
2568 /* Zero filled, number of digits equal to the number of X's. */
2569 sprintf (&template[k
], "%0*d", len
-k
, seqnum
++);
2578 /* Emulate getpwuid, getpwnam and others. */
2580 #define PASSWD_FIELD_SIZE 256
2582 static char my_passwd_name
[PASSWD_FIELD_SIZE
];
2583 static char my_passwd_dir
[MAXPATHLEN
+1];
2585 static struct passwd my_passwd
=
2591 static struct group my_group
=
2593 /* There are no groups on the mac, so we just return "root" as the
2599 /* Initialized by main () in macterm.c to pathname of emacs directory. */
2601 char emacs_passwd_dir
[MAXPATHLEN
+1];
2607 init_emacs_passwd_dir ()
2611 if (getwd (emacs_passwd_dir
) && getwd (my_passwd_dir
))
2613 /* Need pathname of first ancestor that begins with "emacs"
2614 since Mac emacs application is somewhere in the emacs-*
2616 int len
= strlen (emacs_passwd_dir
);
2618 /* j points to the "/" following the directory name being
2621 while (i
>= 0 && !found
)
2623 while (i
>= 0 && emacs_passwd_dir
[i
] != '/')
2625 if (emacs_passwd_dir
[i
] == '/' && i
+5 < len
)
2626 found
= (strncmp (&(emacs_passwd_dir
[i
+1]), "emacs", 5) == 0);
2628 emacs_passwd_dir
[j
+1] = '\0';
2639 /* Setting to "/" probably won't work but set it to something
2641 strcpy (emacs_passwd_dir
, "/");
2642 strcpy (my_passwd_dir
, "/");
2647 static struct passwd emacs_passwd
=
2653 static int my_passwd_inited
= 0;
2661 /* Note: my_passwd_dir initialized in int_emacs_passwd_dir to
2662 directory where Emacs was started. */
2664 owner_name
= (char **) GetResource ('STR ',-16096);
2668 BlockMove ((unsigned char *) *owner_name
,
2669 (unsigned char *) my_passwd_name
,
2671 HUnlock (owner_name
);
2672 p2cstr ((unsigned char *) my_passwd_name
);
2675 my_passwd_name
[0] = 0;
2680 getpwuid (uid_t uid
)
2682 if (!my_passwd_inited
)
2685 my_passwd_inited
= 1;
2693 getgrgid (gid_t gid
)
2700 getpwnam (const char *name
)
2702 if (strcmp (name
, "emacs") == 0)
2703 return &emacs_passwd
;
2705 if (!my_passwd_inited
)
2708 my_passwd_inited
= 1;
2715 /* The functions fork, kill, sigsetmask, sigblock, request_sigio,
2716 setpgrp, setpriority, and unrequest_sigio are defined to be empty
2737 error ("Can't spawn subshell");
2742 request_sigio (void)
2748 unrequest_sigio (void)
2763 pipe (int _fildes
[2])
2770 /* Hard and symbolic links. */
2773 symlink (const char *name1
, const char *name2
)
2781 link (const char *name1
, const char *name2
)
2787 #endif /* ! MAC_OSX */
2789 /* Determine the path name of the file specified by VREFNUM, DIRID,
2790 and NAME and place that in the buffer PATH of length
2793 path_from_vol_dir_name (char *path
, int man_path_len
, short vol_ref_num
,
2794 long dir_id
, ConstStr255Param name
)
2800 if (strlen (name
) > man_path_len
)
2803 memcpy (dir_name
, name
, name
[0]+1);
2804 memcpy (path
, name
, name
[0]+1);
2807 cipb
.dirInfo
.ioDrParID
= dir_id
;
2808 cipb
.dirInfo
.ioNamePtr
= dir_name
;
2812 cipb
.dirInfo
.ioVRefNum
= vol_ref_num
;
2813 cipb
.dirInfo
.ioFDirIndex
= -1;
2814 cipb
.dirInfo
.ioDrDirID
= cipb
.dirInfo
.ioDrParID
;
2815 /* go up to parent each time */
2817 err
= PBGetCatInfo (&cipb
, false);
2822 if (strlen (dir_name
) + strlen (path
) + 1 >= man_path_len
)
2825 strcat (dir_name
, ":");
2826 strcat (dir_name
, path
);
2827 /* attach to front since we're going up directory tree */
2828 strcpy (path
, dir_name
);
2830 while (cipb
.dirInfo
.ioDrDirID
!= fsRtDirID
);
2831 /* stop when we see the volume's root directory */
2833 return 1; /* success */
2838 posix_pathname_to_fsspec (ufn
, fs
)
2842 Str255 mac_pathname
;
2844 if (posix_to_mac_pathname (ufn
, mac_pathname
, sizeof (mac_pathname
)) == 0)
2848 c2pstr (mac_pathname
);
2849 return FSMakeFSSpec (0, 0, mac_pathname
, fs
);
2854 fsspec_to_posix_pathname (fs
, ufn
, ufnbuflen
)
2859 char mac_pathname
[MAXPATHLEN
];
2861 if (path_from_vol_dir_name (mac_pathname
, sizeof (mac_pathname
) - 1,
2862 fs
->vRefNum
, fs
->parID
, fs
->name
)
2863 && mac_to_posix_pathname (mac_pathname
, ufn
, ufnbuflen
))
2872 readlink (const char *path
, char *buf
, int bufsiz
)
2874 char mac_sym_link_name
[MAXPATHLEN
+1];
2877 Boolean target_is_folder
, was_aliased
;
2878 Str255 directory_name
, mac_pathname
;
2881 if (posix_to_mac_pathname (path
, mac_sym_link_name
, MAXPATHLEN
+1) == 0)
2884 c2pstr (mac_sym_link_name
);
2885 err
= FSMakeFSSpec (0, 0, mac_sym_link_name
, &fsspec
);
2892 err
= ResolveAliasFile (&fsspec
, true, &target_is_folder
, &was_aliased
);
2893 if (err
!= noErr
|| !was_aliased
)
2899 if (path_from_vol_dir_name (mac_pathname
, 255, fsspec
.vRefNum
, fsspec
.parID
,
2906 if (mac_to_posix_pathname (mac_pathname
, buf
, bufsiz
) == 0)
2912 return strlen (buf
);
2916 /* Convert a path to one with aliases fully expanded. */
2919 find_true_pathname (const char *path
, char *buf
, int bufsiz
)
2921 char *q
, temp
[MAXPATHLEN
+1];
2925 if (bufsiz
<= 0 || path
== 0 || path
[0] == '\0')
2932 q
= strchr (p
+ 1, '/');
2934 q
= strchr (p
, '/');
2935 len
= 0; /* loop may not be entered, e.g., for "/" */
2940 strncat (temp
, p
, q
- p
);
2941 len
= readlink (temp
, buf
, bufsiz
);
2944 if (strlen (temp
) + 1 > bufsiz
)
2954 if (len
+ strlen (p
) + 1 >= bufsiz
)
2958 return len
+ strlen (p
);
2963 umask (mode_t numask
)
2965 static mode_t mask
= 022;
2966 mode_t oldmask
= mask
;
2973 chmod (const char *path
, mode_t mode
)
2975 /* say it always succeed for now */
2981 fchmod (int fd
, mode_t mode
)
2983 /* say it always succeed for now */
2989 fchown (int fd
, uid_t owner
, gid_t group
)
2991 /* say it always succeed for now */
3000 return fcntl (oldd
, F_DUPFD
, 0);
3002 /* current implementation of fcntl in fcntl.mac.c simply returns old
3004 return fcntl (oldd
, F_DUPFD
);
3011 /* This is from the original sysdep.c. Emulate BSD dup2. First close
3012 newd if it already exists. Then, attempt to dup oldd. If not
3013 successful, call dup2 recursively until we are, then close the
3014 unsuccessful ones. */
3017 dup2 (int oldd
, int newd
)
3028 ret
= dup2 (oldd
, newd
);
3034 /* let it fail for now */
3051 ioctl (int d
, int request
, void *argp
)
3061 if (fildes
>=0 && fildes
<= 2)
3094 #endif /* __MRC__ */
3098 #if __MSL__ < 0x6000
3106 #endif /* __MWERKS__ */
3108 #endif /* ! MAC_OSX */
3111 /* Return the path to the directory in which Emacs can create
3112 temporary files. The MacOS "temporary items" directory cannot be
3113 used because it removes the file written by a process when it
3114 exits. In that sense it's more like "/dev/null" than "/tmp" (but
3115 again not exactly). And of course Emacs needs to read back the
3116 files written by its subprocesses. So here we write the files to a
3117 directory "Emacs" in the Preferences Folder. This directory is
3118 created if it does not exist. */
3121 get_temp_dir_name ()
3123 static char *temp_dir_name
= NULL
;
3127 Str255 dir_name
, full_path
;
3129 char unix_dir_name
[MAXPATHLEN
+1];
3132 /* Cache directory name with pointer temp_dir_name.
3133 Look for it only the first time. */
3136 err
= FindFolder (kOnSystemDisk
, kPreferencesFolderType
, kCreateFolder
,
3137 &vol_ref_num
, &dir_id
);
3141 if (!path_from_vol_dir_name (full_path
, 255, vol_ref_num
, dir_id
, "\p"))
3144 if (strlen (full_path
) + 6 <= MAXPATHLEN
)
3145 strcat (full_path
, "Emacs:");
3149 if (!mac_to_posix_pathname (full_path
, unix_dir_name
, MAXPATHLEN
+1))
3152 dir
= opendir (unix_dir_name
); /* check whether temp directory exists */
3155 else if (mkdir (unix_dir_name
, 0700) != 0) /* create it if not */
3158 temp_dir_name
= (char *) malloc (strlen (unix_dir_name
) + 1);
3159 strcpy (temp_dir_name
, unix_dir_name
);
3162 return temp_dir_name
;
3167 /* Allocate and construct an array of pointers to strings from a list
3168 of strings stored in a 'STR#' resource. The returned pointer array
3169 is stored in the style of argv and environ: if the 'STR#' resource
3170 contains numString strings, a pointer array with numString+1
3171 elements is returned in which the last entry contains a null
3172 pointer. The pointer to the pointer array is passed by pointer in
3173 parameter t. The resource ID of the 'STR#' resource is passed in
3174 parameter StringListID.
3178 get_string_list (char ***t
, short string_list_id
)
3184 h
= GetResource ('STR#', string_list_id
);
3189 num_strings
= * (short *) p
;
3191 *t
= (char **) malloc (sizeof (char *) * (num_strings
+ 1));
3192 for (i
= 0; i
< num_strings
; i
++)
3194 short length
= *p
++;
3195 (*t
)[i
] = (char *) malloc (length
+ 1);
3196 strncpy ((*t
)[i
], p
, length
);
3197 (*t
)[i
][length
] = '\0';
3200 (*t
)[num_strings
] = 0;
3205 /* Return no string in case GetResource fails. Bug fixed by
3206 Ikegami Tsutomu. Caused MPW build to crash without sym -on
3207 option (no sym -on implies -opt local). */
3208 *t
= (char **) malloc (sizeof (char *));
3215 get_path_to_system_folder ()
3220 Str255 dir_name
, full_path
;
3222 static char system_folder_unix_name
[MAXPATHLEN
+1];
3225 err
= FindFolder (kOnSystemDisk
, kSystemFolderType
, kDontCreateFolder
,
3226 &vol_ref_num
, &dir_id
);
3230 if (!path_from_vol_dir_name (full_path
, 255, vol_ref_num
, dir_id
, "\p"))
3233 if (!mac_to_posix_pathname (full_path
, system_folder_unix_name
,
3237 return system_folder_unix_name
;
3243 #define ENVIRON_STRING_LIST_ID 128
3245 /* Get environment variable definitions from STR# resource. */
3252 get_string_list (&environ
, ENVIRON_STRING_LIST_ID
);
3258 /* Make HOME directory the one Emacs starts up in if not specified
3260 if (getenv ("HOME") == NULL
)
3262 environ
= (char **) realloc (environ
, sizeof (char *) * (i
+ 2));
3265 environ
[i
] = (char *) malloc (strlen (my_passwd_dir
) + 6);
3268 strcpy (environ
[i
], "HOME=");
3269 strcat (environ
[i
], my_passwd_dir
);
3276 /* Make HOME directory the one Emacs starts up in if not specified
3278 if (getenv ("MAIL") == NULL
)
3280 environ
= (char **) realloc (environ
, sizeof (char *) * (i
+ 2));
3283 char * path_to_system_folder
= get_path_to_system_folder ();
3284 environ
[i
] = (char *) malloc (strlen (path_to_system_folder
) + 22);
3287 strcpy (environ
[i
], "MAIL=");
3288 strcat (environ
[i
], path_to_system_folder
);
3289 strcat (environ
[i
], "Eudora Folder/In");
3297 /* Return the value of the environment variable NAME. */
3300 getenv (const char *name
)
3302 int length
= strlen(name
);
3305 for (e
= environ
; *e
!= 0; e
++)
3306 if (strncmp(*e
, name
, length
) == 0 && (*e
)[length
] == '=')
3307 return &(*e
)[length
+ 1];
3309 if (strcmp (name
, "TMPDIR") == 0)
3310 return get_temp_dir_name ();
3317 /* see Interfaces&Libraries:Interfaces:CIncludes:signal.h */
3318 char *sys_siglist
[] =
3320 "Zero is not a signal!!!",
3322 "Interactive user interrupt", /* 2 */ "?",
3323 "Floating point exception", /* 4 */ "?", "?", "?",
3324 "Illegal instruction", /* 8 */ "?", "?", "?", "?", "?", "?", "?",
3325 "Segment violation", /* 16 */ "?", "?", "?", "?", "?", "?", "?",
3326 "?", "?", "?", "?", "?", "?", "?", "?",
3330 char *sys_siglist
[] =
3332 "Zero is not a signal!!!",
3334 "Floating point exception",
3335 "Illegal instruction",
3336 "Interactive user interrupt",
3337 "Segment violation",
3340 #else /* not __MRC__ and not __MWERKS__ */
3342 #endif /* not __MRC__ and not __MWERKS__ */
3345 #include <utsname.h>
3348 uname (struct utsname
*name
)
3351 system_name
= GetString (-16413); /* IM - Resource Manager Reference */
3354 BlockMove (*system_name
, name
->nodename
, (*system_name
)[0]+1);
3355 p2cstr (name
->nodename
);
3363 /* Event class of HLE sent to subprocess. */
3364 const OSType kEmacsSubprocessSend
= 'ESND';
3366 /* Event class of HLE sent back from subprocess. */
3367 const OSType kEmacsSubprocessReply
= 'ERPY';
3371 mystrchr (char *s
, char c
)
3373 while (*s
&& *s
!= c
)
3401 mystrcpy (char *to
, char *from
)
3413 /* Start a Mac subprocess. Arguments for it is passed in argv (null
3414 terminated). The process should run with the default directory
3415 "workdir", read input from "infn", and write output and error to
3416 "outfn" and "errfn", resp. The Process Manager call
3417 LaunchApplication is used to start the subprocess. We use high
3418 level events as the mechanism to pass arguments to the subprocess
3419 and to make Emacs wait for the subprocess to terminate and pass
3420 back a result code. The bulk of the code here packs the arguments
3421 into one message to be passed together with the high level event.
3422 Emacs also sometimes starts a subprocess using a shell to perform
3423 wildcard filename expansion. Since we don't really have a shell on
3424 the Mac, this case is detected and the starting of the shell is
3425 by-passed. We really need to add code here to do filename
3426 expansion to support such functionality.
3428 We can't use this strategy in Carbon because the High Level Event
3429 APIs are not available. */
3432 run_mac_command (argv
, workdir
, infn
, outfn
, errfn
)
3433 unsigned char **argv
;
3434 const char *workdir
;
3435 const char *infn
, *outfn
, *errfn
;
3437 #if TARGET_API_MAC_CARBON
3439 #else /* not TARGET_API_MAC_CARBON */
3440 char macappname
[MAXPATHLEN
+1], macworkdir
[MAXPATHLEN
+1];
3441 char macinfn
[MAXPATHLEN
+1], macoutfn
[MAXPATHLEN
+1], macerrfn
[MAXPATHLEN
+1];
3442 int paramlen
, argc
, newargc
, j
, retries
;
3443 char **newargv
, *param
, *p
;
3446 LaunchParamBlockRec lpbr
;
3447 EventRecord send_event
, reply_event
;
3448 RgnHandle cursor_region_handle
;
3450 unsigned long ref_con
, len
;
3452 if (posix_to_mac_pathname (workdir
, macworkdir
, MAXPATHLEN
+1) == 0)
3454 if (posix_to_mac_pathname (infn
, macinfn
, MAXPATHLEN
+1) == 0)
3456 if (posix_to_mac_pathname (outfn
, macoutfn
, MAXPATHLEN
+1) == 0)
3458 if (posix_to_mac_pathname (errfn
, macerrfn
, MAXPATHLEN
+1) == 0)
3461 paramlen
= strlen (macworkdir
) + strlen (macinfn
) + strlen (macoutfn
)
3462 + strlen (macerrfn
) + 4; /* count nulls at end of strings */
3471 /* If a subprocess is invoked with a shell, we receive 3 arguments
3472 of the form: "<path to emacs bins>/sh" "-c" "<path to emacs
3473 bins>/<command> <command args>" */
3474 j
= strlen (argv
[0]);
3475 if (j
>= 3 && strcmp (argv
[0]+j
-3, "/sh") == 0
3476 && argc
== 3 && strcmp (argv
[1], "-c") == 0)
3478 char *command
, *t
, tempmacpathname
[MAXPATHLEN
+1];
3480 /* The arguments for the command in argv[2] are separated by
3481 spaces. Count them and put the count in newargc. */
3482 command
= (char *) alloca (strlen (argv
[2])+2);
3483 strcpy (command
, argv
[2]);
3484 if (command
[strlen (command
) - 1] != ' ')
3485 strcat (command
, " ");
3489 t
= mystrchr (t
, ' ');
3493 t
= mystrchr (t
+1, ' ');
3496 newargv
= (char **) alloca (sizeof (char *) * newargc
);
3499 for (j
= 0; j
< newargc
; j
++)
3501 newargv
[j
] = (char *) alloca (strlen (t
) + 1);
3502 mystrcpy (newargv
[j
], t
);
3505 paramlen
+= strlen (newargv
[j
]) + 1;
3508 if (strncmp (newargv
[0], "~emacs/", 7) == 0)
3510 if (posix_to_mac_pathname (newargv
[0], tempmacpathname
, MAXPATHLEN
+1)
3515 { /* sometimes Emacs call "sh" without a path for the command */
3517 char *t
= (char *) alloca (strlen (newargv
[0]) + 7 + 1);
3518 strcpy (t
, "~emacs/");
3519 strcat (t
, newargv
[0]);
3522 openp (Vexec_path
, build_string (newargv
[0]), Vexec_suffixes
, &path
,
3523 make_number (X_OK
));
3527 if (posix_to_mac_pathname (SDATA (path
), tempmacpathname
,
3531 strcpy (macappname
, tempmacpathname
);
3535 if (posix_to_mac_pathname (argv
[0], macappname
, MAXPATHLEN
+1) == 0)
3538 newargv
= (char **) alloca (sizeof (char *) * argc
);
3540 for (j
= 1; j
< argc
; j
++)
3542 if (strncmp (argv
[j
], "~emacs/", 7) == 0)
3544 char *t
= strchr (argv
[j
], ' ');
3547 char tempcmdname
[MAXPATHLEN
+1], tempmaccmdname
[MAXPATHLEN
+1];
3548 strncpy (tempcmdname
, argv
[j
], t
-argv
[j
]);
3549 tempcmdname
[t
-argv
[j
]] = '\0';
3550 if (posix_to_mac_pathname (tempcmdname
, tempmaccmdname
,
3553 newargv
[j
] = (char *) alloca (strlen (tempmaccmdname
)
3555 strcpy (newargv
[j
], tempmaccmdname
);
3556 strcat (newargv
[j
], t
);
3560 char tempmaccmdname
[MAXPATHLEN
+1];
3561 if (posix_to_mac_pathname (argv
[j
], tempmaccmdname
,
3564 newargv
[j
] = (char *) alloca (strlen (tempmaccmdname
)+1);
3565 strcpy (newargv
[j
], tempmaccmdname
);
3569 newargv
[j
] = argv
[j
];
3570 paramlen
+= strlen (newargv
[j
]) + 1;
3574 /* After expanding all the arguments, we now know the length of the
3575 parameter block to be sent to the subprocess as a message
3576 attached to the HLE. */
3577 param
= (char *) malloc (paramlen
+ 1);
3583 /* first byte of message contains number of arguments for command */
3584 strcpy (p
, macworkdir
);
3585 p
+= strlen (macworkdir
);
3587 /* null terminate strings sent so it's possible to use strcpy over there */
3588 strcpy (p
, macinfn
);
3589 p
+= strlen (macinfn
);
3591 strcpy (p
, macoutfn
);
3592 p
+= strlen (macoutfn
);
3594 strcpy (p
, macerrfn
);
3595 p
+= strlen (macerrfn
);
3597 for (j
= 1; j
< newargc
; j
++)
3599 strcpy (p
, newargv
[j
]);
3600 p
+= strlen (newargv
[j
]);
3604 c2pstr (macappname
);
3606 iErr
= FSMakeFSSpec (0, 0, macappname
, &spec
);
3614 lpbr
.launchBlockID
= extendedBlock
;
3615 lpbr
.launchEPBLength
= extendedBlockLen
;
3616 lpbr
.launchControlFlags
= launchContinue
+ launchNoFileFlags
;
3617 lpbr
.launchAppSpec
= &spec
;
3618 lpbr
.launchAppParameters
= NULL
;
3620 iErr
= LaunchApplication (&lpbr
); /* call the subprocess */
3627 send_event
.what
= kHighLevelEvent
;
3628 send_event
.message
= kEmacsSubprocessSend
;
3629 /* Event ID stored in "where" unused */
3632 /* OS may think current subprocess has terminated if previous one
3633 terminated recently. */
3636 iErr
= PostHighLevelEvent (&send_event
, &lpbr
.launchProcessSN
, 0, param
,
3637 paramlen
+ 1, receiverIDisPSN
);
3639 while (iErr
== sessClosedErr
&& retries
-- > 0);
3647 cursor_region_handle
= NewRgn ();
3649 /* Wait for the subprocess to finish, when it will send us a ERPY
3650 high level event. */
3652 if (WaitNextEvent (highLevelEventMask
, &reply_event
, 180,
3653 cursor_region_handle
)
3654 && reply_event
.message
== kEmacsSubprocessReply
)
3657 /* The return code is sent through the refCon */
3658 iErr
= AcceptHighLevelEvent (&targ
, &ref_con
, NULL
, &len
);
3661 DisposeHandle ((Handle
) cursor_region_handle
);
3666 DisposeHandle ((Handle
) cursor_region_handle
);
3670 #endif /* not TARGET_API_MAC_CARBON */
3675 opendir (const char *dirname
)
3677 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
3678 char mac_pathname
[MAXPATHLEN
+1], vol_name
[MAXPATHLEN
+1];
3682 int len
, vol_name_len
;
3684 if (find_true_pathname (dirname
, true_pathname
, MAXPATHLEN
+1) == -1)
3687 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
3689 fully_resolved_name
[len
] = '\0';
3691 strcpy (fully_resolved_name
, true_pathname
);
3693 dirp
= (DIR *) malloc (sizeof(DIR));
3697 /* Handle special case when dirname is "/": sets up for readir to
3698 get all mount volumes. */
3699 if (strcmp (fully_resolved_name
, "/") == 0)
3701 dirp
->getting_volumes
= 1; /* special all mounted volumes DIR struct */
3702 dirp
->current_index
= 1; /* index for first volume */
3706 /* Handle typical cases: not accessing all mounted volumes. */
3707 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
3710 /* Emacs calls opendir without the trailing '/', Mac needs trailing ':' */
3711 len
= strlen (mac_pathname
);
3712 if (mac_pathname
[len
- 1] != ':' && len
< MAXPATHLEN
)
3713 strcat (mac_pathname
, ":");
3715 /* Extract volume name */
3716 vol_name_len
= strchr (mac_pathname
, ':') - mac_pathname
;
3717 strncpy (vol_name
, mac_pathname
, vol_name_len
);
3718 vol_name
[vol_name_len
] = '\0';
3719 strcat (vol_name
, ":");
3721 c2pstr (mac_pathname
);
3722 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
3723 /* using full pathname so vRefNum and DirID ignored */
3724 cipb
.hFileInfo
.ioVRefNum
= 0;
3725 cipb
.hFileInfo
.ioDirID
= 0;
3726 cipb
.hFileInfo
.ioFDirIndex
= 0;
3727 /* set to 0 to get information about specific dir or file */
3729 errno
= PBGetCatInfo (&cipb
, false);
3736 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x10)) /* bit 4 = 1 for directories */
3737 return 0; /* not a directory */
3739 dirp
->dir_id
= cipb
.dirInfo
.ioDrDirID
; /* used later in readdir */
3740 dirp
->getting_volumes
= 0;
3741 dirp
->current_index
= 1; /* index for first file/directory */
3744 vpb
.ioNamePtr
= vol_name
;
3745 /* using full pathname so vRefNum and DirID ignored */
3747 vpb
.ioVolIndex
= -1;
3748 errno
= PBHGetVInfo ((union HParamBlockRec
*) &vpb
, false);
3755 dirp
->vol_ref_num
= vpb
.ioVRefNum
;
3772 HParamBlockRec hpblock
;
3774 static struct dirent s_dirent
;
3775 static Str255 s_name
;
3779 /* Handle the root directory containing the mounted volumes. Call
3780 PBHGetVInfo specifying an index to obtain the info for a volume.
3781 PBHGetVInfo returns an error when it receives an index beyond the
3782 last volume, at which time we should return a nil dirent struct
3784 if (dp
->getting_volumes
)
3786 hpblock
.volumeParam
.ioNamePtr
= s_name
;
3787 hpblock
.volumeParam
.ioVRefNum
= 0;
3788 hpblock
.volumeParam
.ioVolIndex
= dp
->current_index
;
3790 errno
= PBHGetVInfo (&hpblock
, false);
3798 strcat (s_name
, "/"); /* need "/" for stat to work correctly */
3800 dp
->current_index
++;
3802 s_dirent
.d_ino
= hpblock
.volumeParam
.ioVRefNum
;
3803 s_dirent
.d_name
= s_name
;
3809 cipb
.hFileInfo
.ioVRefNum
= dp
->vol_ref_num
;
3810 cipb
.hFileInfo
.ioNamePtr
= s_name
;
3811 /* location to receive filename returned */
3813 /* return only visible files */
3817 cipb
.hFileInfo
.ioDirID
= dp
->dir_id
;
3818 /* directory ID found by opendir */
3819 cipb
.hFileInfo
.ioFDirIndex
= dp
->current_index
;
3821 errno
= PBGetCatInfo (&cipb
, false);
3828 /* insist on a visible entry */
3829 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* directory? */
3830 done
= !(cipb
.dirInfo
.ioDrUsrWds
.frFlags
& fInvisible
);
3832 done
= !(cipb
.hFileInfo
.ioFlFndrInfo
.fdFlags
& fInvisible
);
3834 dp
->current_index
++;
3847 s_dirent
.d_ino
= cipb
.dirInfo
.ioDrDirID
;
3848 /* value unimportant: non-zero for valid file */
3849 s_dirent
.d_name
= s_name
;
3859 char mac_pathname
[MAXPATHLEN
+1];
3860 Str255 directory_name
;
3864 if (path_from_vol_dir_name (mac_pathname
, 255, 0, 0, "\p") == 0)
3867 if (mac_to_posix_pathname (mac_pathname
, path
, MAXPATHLEN
+1) == 0)
3873 #endif /* ! MAC_OSX */
3877 initialize_applescript ()
3882 /* if open fails, as_scripting_component is set to NULL. Its
3883 subsequent use in OSA calls will fail with badComponentInstance
3885 as_scripting_component
= OpenDefaultComponent (kOSAComponentType
,
3886 kAppleScriptSubtype
);
3888 null_desc
.descriptorType
= typeNull
;
3889 null_desc
.dataHandle
= 0;
3890 osaerror
= OSAMakeContext (as_scripting_component
, &null_desc
,
3891 kOSANullScript
, &as_script_context
);
3893 as_script_context
= kOSANullScript
;
3894 /* use default context if create fails */
3899 terminate_applescript()
3901 OSADispose (as_scripting_component
, as_script_context
);
3902 CloseComponent (as_scripting_component
);
3905 /* Convert a lisp string to the 4 byte character code. */
3908 mac_get_code_from_arg(Lisp_Object arg
, OSType defCode
)
3917 /* check type string */
3919 if (SBYTES (arg
) != 4)
3921 error ("Wrong argument: need string of length 4 for code");
3923 result
= EndianU32_BtoN (*((UInt32
*) SDATA (arg
)));
3928 /* Convert the 4 byte character code into a 4 byte string. */
3931 mac_get_object_from_code(OSType defCode
)
3933 UInt32 code
= EndianU32_NtoB (defCode
);
3935 return make_unibyte_string ((char *)&code
, 4);
3939 DEFUN ("mac-get-file-creator", Fmac_get_file_creator
, Smac_get_file_creator
, 1, 1, 0,
3940 doc
: /* Get the creator code of FILENAME as a four character string. */)
3942 Lisp_Object filename
;
3951 Lisp_Object result
= Qnil
;
3952 CHECK_STRING (filename
);
3954 if (NILP(Ffile_exists_p(filename
)) || !NILP(Ffile_directory_p(filename
))) {
3957 filename
= Fexpand_file_name (filename
, Qnil
);
3961 status
= FSPathMakeRef(SDATA(ENCODE_FILE(filename
)), &fref
, NULL
);
3963 status
= posix_pathname_to_fsspec (SDATA (ENCODE_FILE (filename
)), &fss
);
3966 if (status
== noErr
)
3969 FSCatalogInfo catalogInfo
;
3971 status
= FSGetCatalogInfo(&fref
, kFSCatInfoFinderInfo
,
3972 &catalogInfo
, NULL
, NULL
, NULL
);
3976 status
= FSpGetFInfo (&fss
, &finder_info
);
3978 if (status
== noErr
)
3981 result
= mac_get_object_from_code(((FileInfo
*)&catalogInfo
.finderInfo
)->fileCreator
);
3983 result
= mac_get_object_from_code (finder_info
.fdCreator
);
3988 if (status
!= noErr
) {
3989 error ("Error while getting file information.");
3994 DEFUN ("mac-get-file-type", Fmac_get_file_type
, Smac_get_file_type
, 1, 1, 0,
3995 doc
: /* Get the type code of FILENAME as a four character string. */)
3997 Lisp_Object filename
;
4006 Lisp_Object result
= Qnil
;
4007 CHECK_STRING (filename
);
4009 if (NILP(Ffile_exists_p(filename
)) || !NILP(Ffile_directory_p(filename
))) {
4012 filename
= Fexpand_file_name (filename
, Qnil
);
4016 status
= FSPathMakeRef(SDATA(ENCODE_FILE(filename
)), &fref
, NULL
);
4018 status
= posix_pathname_to_fsspec (SDATA (ENCODE_FILE (filename
)), &fss
);
4021 if (status
== noErr
)
4024 FSCatalogInfo catalogInfo
;
4026 status
= FSGetCatalogInfo(&fref
, kFSCatInfoFinderInfo
,
4027 &catalogInfo
, NULL
, NULL
, NULL
);
4031 status
= FSpGetFInfo (&fss
, &finder_info
);
4033 if (status
== noErr
)
4036 result
= mac_get_object_from_code(((FileInfo
*)&catalogInfo
.finderInfo
)->fileType
);
4038 result
= mac_get_object_from_code (finder_info
.fdType
);
4043 if (status
!= noErr
) {
4044 error ("Error while getting file information.");
4049 DEFUN ("mac-set-file-creator", Fmac_set_file_creator
, Smac_set_file_creator
, 1, 2, 0,
4050 doc
: /* Set creator code of file FILENAME to CODE.
4051 If non-nil, CODE must be a 4-character string. Otherwise, 'EMAx' is
4052 assumed. Return non-nil if successful. */)
4054 Lisp_Object filename
, code
;
4063 CHECK_STRING (filename
);
4065 cCode
= mac_get_code_from_arg(code
, 'EMAx');
4067 if (NILP(Ffile_exists_p(filename
)) || !NILP(Ffile_directory_p(filename
))) {
4070 filename
= Fexpand_file_name (filename
, Qnil
);
4074 status
= FSPathMakeRef(SDATA(ENCODE_FILE(filename
)), &fref
, NULL
);
4076 status
= posix_pathname_to_fsspec (SDATA (ENCODE_FILE (filename
)), &fss
);
4079 if (status
== noErr
)
4082 FSCatalogInfo catalogInfo
;
4084 status
= FSGetCatalogInfo(&fref
, kFSCatInfoFinderInfo
,
4085 &catalogInfo
, NULL
, NULL
, &parentDir
);
4089 status
= FSpGetFInfo (&fss
, &finder_info
);
4091 if (status
== noErr
)
4094 ((FileInfo
*)&catalogInfo
.finderInfo
)->fileCreator
= cCode
;
4095 status
= FSSetCatalogInfo(&fref
, kFSCatInfoFinderInfo
, &catalogInfo
);
4096 /* TODO: on Mac OS 10.2, we need to touch the parent dir, FNNotify? */
4098 finder_info
.fdCreator
= cCode
;
4099 status
= FSpSetFInfo (&fss
, &finder_info
);
4104 if (status
!= noErr
) {
4105 error ("Error while setting creator information.");
4110 DEFUN ("mac-set-file-type", Fmac_set_file_type
, Smac_set_file_type
, 2, 2, 0,
4111 doc
: /* Set file code of file FILENAME to CODE.
4112 CODE must be a 4-character string. Return non-nil if successful. */)
4114 Lisp_Object filename
, code
;
4123 CHECK_STRING (filename
);
4125 cCode
= mac_get_code_from_arg(code
, 0); /* Default to empty code*/
4127 if (NILP(Ffile_exists_p(filename
)) || !NILP(Ffile_directory_p(filename
))) {
4130 filename
= Fexpand_file_name (filename
, Qnil
);
4134 status
= FSPathMakeRef(SDATA(ENCODE_FILE(filename
)), &fref
, NULL
);
4136 status
= posix_pathname_to_fsspec (SDATA (ENCODE_FILE (filename
)), &fss
);
4139 if (status
== noErr
)
4142 FSCatalogInfo catalogInfo
;
4144 status
= FSGetCatalogInfo(&fref
, kFSCatInfoFinderInfo
,
4145 &catalogInfo
, NULL
, NULL
, &parentDir
);
4149 status
= FSpGetFInfo (&fss
, &finder_info
);
4151 if (status
== noErr
)
4154 ((FileInfo
*)&catalogInfo
.finderInfo
)->fileType
= cCode
;
4155 status
= FSSetCatalogInfo(&fref
, kFSCatInfoFinderInfo
, &catalogInfo
);
4156 /* TODO: on Mac OS 10.2, we need to touch the parent dir, FNNotify? */
4158 finder_info
.fdType
= cCode
;
4159 status
= FSpSetFInfo (&fss
, &finder_info
);
4164 if (status
!= noErr
) {
4165 error ("Error while setting creator information.");
4171 /* Compile and execute the AppleScript SCRIPT and return the error
4172 status as function value. A zero is returned if compilation and
4173 execution is successful, in which case *RESULT is set to a Lisp
4174 string containing the resulting script value. Otherwise, the Mac
4175 error code is returned and *RESULT is set to an error Lisp string.
4176 For documentation on the MacOS scripting architecture, see Inside
4177 Macintosh - Interapplication Communications: Scripting
4181 do_applescript (script
, result
)
4182 Lisp_Object script
, *result
;
4184 AEDesc script_desc
, result_desc
, error_desc
, *desc
= NULL
;
4190 if (!as_scripting_component
)
4191 initialize_applescript();
4193 error
= AECreateDesc (typeChar
, SDATA (script
), SBYTES (script
),
4198 osaerror
= OSADoScript (as_scripting_component
, &script_desc
, kOSANullScript
,
4199 typeChar
, kOSAModeNull
, &result_desc
);
4201 if (osaerror
== noErr
)
4202 /* success: retrieve resulting script value */
4203 desc
= &result_desc
;
4204 else if (osaerror
== errOSAScriptError
)
4205 /* error executing AppleScript: retrieve error message */
4206 if (!OSAScriptError (as_scripting_component
, kOSAErrorMessage
, typeChar
,
4212 #if TARGET_API_MAC_CARBON
4213 *result
= make_uninit_string (AEGetDescDataSize (desc
));
4214 AEGetDescData (desc
, SDATA (*result
), SBYTES (*result
));
4215 #else /* not TARGET_API_MAC_CARBON */
4216 *result
= make_uninit_string (GetHandleSize (desc
->dataHandle
));
4217 memcpy (SDATA (*result
), *(desc
->dataHandle
), SBYTES (*result
));
4218 #endif /* not TARGET_API_MAC_CARBON */
4219 AEDisposeDesc (desc
);
4222 AEDisposeDesc (&script_desc
);
4228 DEFUN ("do-applescript", Fdo_applescript
, Sdo_applescript
, 1, 1, 0,
4229 doc
: /* Compile and execute AppleScript SCRIPT and return the result.
4230 If compilation and execution are successful, the resulting script
4231 value is returned as a string. Otherwise the function aborts and
4232 displays the error message returned by the AppleScript scripting
4240 CHECK_STRING (script
);
4243 status
= do_applescript (script
, &result
);
4247 else if (!STRINGP (result
))
4248 error ("AppleScript error %d", status
);
4250 error ("%s", SDATA (result
));
4254 DEFUN ("mac-file-name-to-posix", Fmac_file_name_to_posix
,
4255 Smac_file_name_to_posix
, 1, 1, 0,
4256 doc
: /* Convert Macintosh FILENAME to Posix form. */)
4258 Lisp_Object filename
;
4260 char posix_filename
[MAXPATHLEN
+1];
4262 CHECK_STRING (filename
);
4264 if (mac_to_posix_pathname (SDATA (filename
), posix_filename
, MAXPATHLEN
))
4265 return build_string (posix_filename
);
4271 DEFUN ("posix-file-name-to-mac", Fposix_file_name_to_mac
,
4272 Sposix_file_name_to_mac
, 1, 1, 0,
4273 doc
: /* Convert Posix FILENAME to Mac form. */)
4275 Lisp_Object filename
;
4277 char mac_filename
[MAXPATHLEN
+1];
4279 CHECK_STRING (filename
);
4281 if (posix_to_mac_pathname (SDATA (filename
), mac_filename
, MAXPATHLEN
))
4282 return build_string (mac_filename
);
4288 DEFUN ("mac-coerce-ae-data", Fmac_coerce_ae_data
, Smac_coerce_ae_data
, 3, 3, 0,
4289 doc
: /* Coerce Apple event data SRC-DATA of type SRC-TYPE to DST-TYPE.
4290 Each type should be a string of length 4 or the symbol
4291 `undecoded-file-name'. */)
4292 (src_type
, src_data
, dst_type
)
4293 Lisp_Object src_type
, src_data
, dst_type
;
4296 Lisp_Object result
= Qnil
;
4297 DescType src_desc_type
, dst_desc_type
;
4305 CHECK_STRING (src_data
);
4306 if (EQ (src_type
, Qundecoded_file_name
))
4307 src_desc_type
= TYPE_FILE_NAME
;
4309 src_desc_type
= mac_get_code_from_arg (src_type
, 0);
4311 if (EQ (dst_type
, Qundecoded_file_name
))
4312 dst_desc_type
= TYPE_FILE_NAME
;
4314 dst_desc_type
= mac_get_code_from_arg (dst_type
, 0);
4317 err
= AECoercePtr (src_desc_type
, SDATA (src_data
), SBYTES (src_data
),
4318 dst_desc_type
, &dst_desc
);
4321 result
= Fcdr (mac_aedesc_to_lisp (&dst_desc
));
4322 AEDisposeDesc (&dst_desc
);
4330 #if TARGET_API_MAC_CARBON
4331 static Lisp_Object Qxml
, Qmime_charset
;
4332 static Lisp_Object QNFD
, QNFKD
, QNFC
, QNFKC
, QHFS_plus_D
, QHFS_plus_C
;
4334 DEFUN ("mac-get-preference", Fmac_get_preference
, Smac_get_preference
, 1, 4, 0,
4335 doc
: /* Return the application preference value for KEY.
4336 KEY is either a string specifying a preference key, or a list of key
4337 strings. If it is a list, the (i+1)-th element is used as a key for
4338 the CFDictionary value obtained by the i-th element. Return nil if
4339 lookup is failed at some stage.
4341 Optional arg APPLICATION is an application ID string. If omitted or
4342 nil, that stands for the current application.
4344 Optional arg FORMAT specifies the data format of the return value. If
4345 omitted or nil, each Core Foundation object is converted into a
4346 corresponding Lisp object as follows:
4348 Core Foundation Lisp Tag
4349 ------------------------------------------------------------
4350 CFString Multibyte string string
4351 CFNumber Integer or float number
4352 CFBoolean Symbol (t or nil) boolean
4353 CFDate List of three integers date
4354 (cf. `current-time')
4355 CFData Unibyte string data
4356 CFArray Vector array
4357 CFDictionary Alist or hash table dictionary
4358 (depending on HASH-BOUND)
4360 If it is t, a symbol that represents the type of the original Core
4361 Foundation object is prepended. If it is `xml', the value is returned
4362 as an XML representation.
4364 Optional arg HASH-BOUND specifies which kinds of the list objects,
4365 alists or hash tables, are used as the targets of the conversion from
4366 CFDictionary. If HASH-BOUND is a negative integer or nil, always
4367 generate alists. If HASH-BOUND >= 0, generate an alist if the number
4368 of keys in the dictionary is smaller than HASH-BOUND, and a hash table
4370 (key
, application
, format
, hash_bound
)
4371 Lisp_Object key
, application
, format
, hash_bound
;
4373 CFStringRef app_id
, key_str
;
4374 CFPropertyListRef app_plist
= NULL
, plist
;
4375 Lisp_Object result
= Qnil
, tmp
;
4378 key
= Fcons (key
, Qnil
);
4382 for (tmp
= key
; CONSP (tmp
); tmp
= XCDR (tmp
))
4383 CHECK_STRING_CAR (tmp
);
4385 wrong_type_argument (Qlistp
, key
);
4387 if (!NILP (application
))
4388 CHECK_STRING (application
);
4389 CHECK_SYMBOL (format
);
4390 if (!NILP (hash_bound
))
4391 CHECK_NUMBER (hash_bound
);
4395 app_id
= kCFPreferencesCurrentApplication
;
4396 if (!NILP (application
))
4398 app_id
= cfstring_create_with_string (application
);
4402 key_str
= cfstring_create_with_string (XCAR (key
));
4403 if (key_str
== NULL
)
4405 app_plist
= CFPreferencesCopyAppValue (key_str
, app_id
);
4406 CFRelease (key_str
);
4407 if (app_plist
== NULL
)
4411 for (key
= XCDR (key
); CONSP (key
); key
= XCDR (key
))
4413 if (CFGetTypeID (plist
) != CFDictionaryGetTypeID ())
4415 key_str
= cfstring_create_with_string (XCAR (key
));
4416 if (key_str
== NULL
)
4418 plist
= CFDictionaryGetValue (plist
, key_str
);
4419 CFRelease (key_str
);
4425 if (EQ (format
, Qxml
))
4427 CFDataRef data
= CFPropertyListCreateXMLData (NULL
, plist
);
4430 result
= cfdata_to_lisp (data
);
4435 cfproperty_list_to_lisp (plist
, EQ (format
, Qt
),
4436 NILP (hash_bound
) ? -1 : XINT (hash_bound
));
4440 CFRelease (app_plist
);
4449 static CFStringEncoding
4450 get_cfstring_encoding_from_lisp (obj
)
4453 CFStringRef iana_name
;
4454 CFStringEncoding encoding
= kCFStringEncodingInvalidId
;
4457 return kCFStringEncodingUnicode
;
4462 if (SYMBOLP (obj
) && !NILP (Fcoding_system_p (obj
)))
4464 Lisp_Object coding_spec
, plist
;
4466 coding_spec
= Fget (obj
, Qcoding_system
);
4467 plist
= XVECTOR (coding_spec
)->contents
[3];
4468 obj
= Fplist_get (XVECTOR (coding_spec
)->contents
[3], Qmime_charset
);
4472 obj
= SYMBOL_NAME (obj
);
4476 iana_name
= cfstring_create_with_string (obj
);
4479 encoding
= CFStringConvertIANACharSetNameToEncoding (iana_name
);
4480 CFRelease (iana_name
);
4487 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
4489 cfstring_create_normalized (str
, symbol
)
4494 TextEncodingVariant variant
;
4495 float initial_mag
= 0.0;
4496 CFStringRef result
= NULL
;
4498 if (EQ (symbol
, QNFD
))
4499 form
= kCFStringNormalizationFormD
;
4500 else if (EQ (symbol
, QNFKD
))
4501 form
= kCFStringNormalizationFormKD
;
4502 else if (EQ (symbol
, QNFC
))
4503 form
= kCFStringNormalizationFormC
;
4504 else if (EQ (symbol
, QNFKC
))
4505 form
= kCFStringNormalizationFormKC
;
4506 else if (EQ (symbol
, QHFS_plus_D
))
4508 variant
= kUnicodeHFSPlusDecompVariant
;
4511 else if (EQ (symbol
, QHFS_plus_C
))
4513 variant
= kUnicodeHFSPlusCompVariant
;
4519 CFMutableStringRef mut_str
= CFStringCreateMutableCopy (NULL
, 0, str
);
4523 CFStringNormalize (mut_str
, form
);
4527 else if (initial_mag
> 0.0)
4529 UnicodeToTextInfo uni
= NULL
;
4532 UniChar
*in_text
, *buffer
= NULL
, *out_buf
= NULL
;
4534 ByteCount out_read
, out_size
, out_len
;
4536 map
.unicodeEncoding
= CreateTextEncoding (kTextEncodingUnicodeDefault
,
4538 kTextEncodingDefaultFormat
);
4539 map
.otherEncoding
= CreateTextEncoding (kTextEncodingUnicodeDefault
,
4541 kTextEncodingDefaultFormat
);
4542 map
.mappingVersion
= kUnicodeUseLatestMapping
;
4544 length
= CFStringGetLength (str
);
4545 out_size
= (int)((float)length
* initial_mag
) * sizeof (UniChar
);
4549 in_text
= (UniChar
*)CFStringGetCharactersPtr (str
);
4550 if (in_text
== NULL
)
4552 buffer
= xmalloc (sizeof (UniChar
) * length
);
4555 CFStringGetCharacters (str
, CFRangeMake (0, length
), buffer
);
4561 err
= CreateUnicodeToTextInfo(&map
, &uni
);
4562 while (err
== noErr
)
4564 out_buf
= xmalloc (out_size
);
4565 if (out_buf
== NULL
)
4568 err
= ConvertFromUnicodeToText (uni
, length
* sizeof (UniChar
),
4570 kUnicodeDefaultDirectionMask
,
4571 0, NULL
, NULL
, NULL
,
4572 out_size
, &out_read
, &out_len
,
4574 if (err
== noErr
&& out_read
< length
* sizeof (UniChar
))
4583 result
= CFStringCreateWithCharacters (NULL
, out_buf
,
4584 out_len
/ sizeof (UniChar
));
4586 DisposeUnicodeToTextInfo (&uni
);
4602 DEFUN ("mac-code-convert-string", Fmac_code_convert_string
, Smac_code_convert_string
, 3, 4, 0,
4603 doc
: /* Convert STRING from SOURCE encoding to TARGET encoding.
4604 The conversion is performed using the converter provided by the system.
4605 Each encoding is specified by either a coding system symbol, a mime
4606 charset string, or an integer as a CFStringEncoding value. Nil for
4607 encoding means UTF-16 in native byte order, no byte order mark.
4608 On Mac OS X 10.2 and later, you can do Unicode Normalization by
4609 specifying the optional argument NORMALIZATION-FORM with a symbol NFD,
4610 NFKD, NFC, NFKC, HFS+D, or HFS+C.
4611 On successful conversion, return the result string, else return nil. */)
4612 (string
, source
, target
, normalization_form
)
4613 Lisp_Object string
, source
, target
, normalization_form
;
4615 Lisp_Object result
= Qnil
;
4616 CFStringEncoding src_encoding
, tgt_encoding
;
4617 CFStringRef str
= NULL
;
4619 CHECK_STRING (string
);
4620 if (!INTEGERP (source
) && !STRINGP (source
))
4621 CHECK_SYMBOL (source
);
4622 if (!INTEGERP (target
) && !STRINGP (target
))
4623 CHECK_SYMBOL (target
);
4624 CHECK_SYMBOL (normalization_form
);
4628 src_encoding
= get_cfstring_encoding_from_lisp (source
);
4629 tgt_encoding
= get_cfstring_encoding_from_lisp (target
);
4631 /* We really want string_to_unibyte, but since it doesn't exist yet, we
4632 use string_as_unibyte which works as well, except for the fact that
4633 it's too permissive (it doesn't check that the multibyte string only
4634 contain single-byte chars). */
4635 string
= Fstring_as_unibyte (string
);
4636 if (src_encoding
!= kCFStringEncodingInvalidId
4637 && tgt_encoding
!= kCFStringEncodingInvalidId
)
4638 str
= CFStringCreateWithBytes (NULL
, SDATA (string
), SBYTES (string
),
4639 src_encoding
, !NILP (source
));
4640 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
4643 CFStringRef saved_str
= str
;
4645 str
= cfstring_create_normalized (saved_str
, normalization_form
);
4646 CFRelease (saved_str
);
4651 CFIndex str_len
, buf_len
;
4653 str_len
= CFStringGetLength (str
);
4654 if (CFStringGetBytes (str
, CFRangeMake (0, str_len
), tgt_encoding
, 0,
4655 !NILP (target
), NULL
, 0, &buf_len
) == str_len
)
4657 result
= make_uninit_string (buf_len
);
4658 CFStringGetBytes (str
, CFRangeMake (0, str_len
), tgt_encoding
, 0,
4659 !NILP (target
), SDATA (result
), buf_len
, NULL
);
4668 #endif /* TARGET_API_MAC_CARBON */
4671 DEFUN ("mac-clear-font-name-table", Fmac_clear_font_name_table
, Smac_clear_font_name_table
, 0, 0, 0,
4672 doc
: /* Clear the font name table. */)
4676 mac_clear_font_name_table ();
4682 mac_get_system_locale ()
4690 lang
= GetScriptVariable (smSystemScript
, smScriptLang
);
4691 region
= GetScriptManagerVariable (smRegionCode
);
4692 err
= LocaleRefFromLangOrRegionCode (lang
, region
, &locale
);
4694 err
= LocaleRefGetPartString (locale
, kLocaleAllPartsMask
,
4697 return build_string (str
);
4706 extern int inhibit_window_system
;
4707 extern int noninteractive
;
4709 /* Unlike in X11, window events in Carbon do not come from sockets.
4710 So we cannot simply use `select' to monitor two kinds of inputs:
4711 window events and process outputs. We emulate such functionality
4712 by regarding fd 0 as the window event channel and simultaneously
4713 monitoring both kinds of input channels. It is implemented by
4714 dividing into some cases:
4715 1. The window event channel is not involved.
4717 2. Sockets are not involved.
4718 -> Use ReceiveNextEvent.
4719 3. [If SELECT_USE_CFSOCKET is defined]
4720 Only the window event channel and socket read channels are
4721 involved, and timeout is not too short (greater than
4722 SELECT_TIMEOUT_THRESHHOLD_RUNLOOP seconds).
4723 -> Create CFSocket for each socket and add it into the current
4724 event RunLoop so that a `ready-to-read' event can be posted
4725 to the event queue that is also used for window events. Then
4726 ReceiveNextEvent can wait for both kinds of inputs.
4728 -> Periodically poll the window input channel while repeatedly
4729 executing `select' with a short timeout
4730 (SELECT_POLLING_PERIOD_USEC microseconds). */
4732 #define SELECT_POLLING_PERIOD_USEC 20000
4733 #ifdef SELECT_USE_CFSOCKET
4734 #define SELECT_TIMEOUT_THRESHOLD_RUNLOOP 0.2
4735 #define EVENT_CLASS_SOCK 'Sock'
4738 socket_callback (s
, type
, address
, data
, info
)
4740 CFSocketCallBackType type
;
4747 CreateEvent (NULL
, EVENT_CLASS_SOCK
, 0, 0, kEventAttributeNone
, &event
);
4748 PostEventToQueue (GetCurrentEventQueue (), event
, kEventPriorityStandard
);
4749 ReleaseEvent (event
);
4751 #endif /* SELECT_USE_CFSOCKET */
4754 select_and_poll_event (n
, rfds
, wfds
, efds
, timeout
)
4759 struct timeval
*timeout
;
4764 r
= select (n
, rfds
, wfds
, efds
, timeout
);
4768 err
= ReceiveNextEvent (0, NULL
, kEventDurationNoWait
,
4769 kEventLeaveInQueue
, NULL
);
4780 #if MAC_OS_X_VERSION_MAX_ALLOWED < 1020
4781 #undef SELECT_INVALIDATE_CFSOCKET
4785 sys_select (n
, rfds
, wfds
, efds
, timeout
)
4790 struct timeval
*timeout
;
4794 EMACS_TIME select_timeout
;
4796 if (inhibit_window_system
|| noninteractive
4797 || rfds
== NULL
|| !FD_ISSET (0, rfds
))
4798 return select (n
, rfds
, wfds
, efds
, timeout
);
4802 if (wfds
== NULL
&& efds
== NULL
)
4805 SELECT_TYPE orfds
= *rfds
;
4807 EventTimeout timeout_sec
=
4809 ? (EMACS_SECS (*timeout
) * kEventDurationSecond
4810 + EMACS_USECS (*timeout
) * kEventDurationMicrosecond
)
4811 : kEventDurationForever
);
4813 for (i
= 1; i
< n
; i
++)
4814 if (FD_ISSET (i
, rfds
))
4820 err
= ReceiveNextEvent (0, NULL
, timeout_sec
,
4821 kEventLeaveInQueue
, NULL
);
4832 /* Avoid initial overhead of RunLoop setup for the case that
4833 some input is already available. */
4834 EMACS_SET_SECS_USECS (select_timeout
, 0, 0);
4835 r
= select_and_poll_event (n
, rfds
, wfds
, efds
, &select_timeout
);
4836 if (r
!= 0 || timeout_sec
== 0.0)
4841 #ifdef SELECT_USE_CFSOCKET
4842 if (timeout_sec
> 0 && timeout_sec
<= SELECT_TIMEOUT_THRESHOLD_RUNLOOP
)
4843 goto poll_periodically
;
4846 CFRunLoopRef runloop
=
4847 (CFRunLoopRef
) GetCFRunLoopFromEventLoop (GetCurrentEventLoop ());
4848 EventTypeSpec specs
[] = {{EVENT_CLASS_SOCK
, 0}};
4849 #ifdef SELECT_INVALIDATE_CFSOCKET
4850 CFSocketRef
*shead
, *s
;
4852 CFRunLoopSourceRef
*shead
, *s
;
4857 #ifdef SELECT_INVALIDATE_CFSOCKET
4858 shead
= xmalloc (sizeof (CFSocketRef
) * nsocks
);
4860 shead
= xmalloc (sizeof (CFRunLoopSourceRef
) * nsocks
);
4863 for (i
= 1; i
< n
; i
++)
4864 if (FD_ISSET (i
, rfds
))
4866 CFSocketRef socket
=
4867 CFSocketCreateWithNative (NULL
, i
, kCFSocketReadCallBack
,
4868 socket_callback
, NULL
);
4869 CFRunLoopSourceRef source
=
4870 CFSocketCreateRunLoopSource (NULL
, socket
, 0);
4872 #ifdef SELECT_INVALIDATE_CFSOCKET
4873 CFSocketSetSocketFlags (socket
, 0);
4875 CFRunLoopAddSource (runloop
, source
, kCFRunLoopDefaultMode
);
4876 #ifdef SELECT_INVALIDATE_CFSOCKET
4886 err
= ReceiveNextEvent (0, NULL
, timeout_sec
, kEventLeaveInQueue
, NULL
);
4891 #ifdef SELECT_INVALIDATE_CFSOCKET
4892 CFSocketInvalidate (*s
);
4894 CFRunLoopRemoveSource (runloop
, *s
, kCFRunLoopDefaultMode
);
4909 FlushEventsMatchingListFromQueue (GetCurrentEventQueue (),
4910 GetEventTypeCount (specs
),
4912 EMACS_SET_SECS_USECS (select_timeout
, 0, 0);
4913 r
= select_and_poll_event (n
, rfds
, wfds
, efds
, &select_timeout
);
4920 #endif /* SELECT_USE_CFSOCKET */
4925 EMACS_TIME end_time
, now
, remaining_time
;
4926 SELECT_TYPE orfds
= *rfds
, owfds
, oefds
;
4934 remaining_time
= *timeout
;
4935 EMACS_GET_TIME (now
);
4936 EMACS_ADD_TIME (end_time
, now
, remaining_time
);
4941 EMACS_SET_SECS_USECS (select_timeout
, 0, SELECT_POLLING_PERIOD_USEC
);
4942 if (timeout
&& EMACS_TIME_LT (remaining_time
, select_timeout
))
4943 select_timeout
= remaining_time
;
4944 r
= select_and_poll_event (n
, rfds
, wfds
, efds
, &select_timeout
);
4956 EMACS_GET_TIME (now
);
4957 EMACS_SUB_TIME (remaining_time
, end_time
, now
);
4960 while (!timeout
|| EMACS_TIME_LT (now
, end_time
));
4971 /* Set up environment variables so that Emacs can correctly find its
4972 support files when packaged as an application bundle. Directories
4973 placed in /usr/local/share/emacs/<emacs-version>/, /usr/local/bin,
4974 and /usr/local/libexec/emacs/<emacs-version>/<system-configuration>
4975 by `make install' by default can instead be placed in
4976 .../Emacs.app/Contents/Resources/ and
4977 .../Emacs.app/Contents/MacOS/. Each of these environment variables
4978 is changed only if it is not already set. Presumably if the user
4979 sets an environment variable, he will want to use files in his path
4980 instead of ones in the application bundle. */
4982 init_mac_osx_environment ()
4986 CFStringRef cf_app_bundle_pathname
;
4987 int app_bundle_pathname_len
;
4988 char *app_bundle_pathname
;
4992 /* Initialize locale related variables. */
4993 mac_system_script_code
=
4994 (ScriptCode
) GetScriptManagerVariable (smSysScript
);
4995 Vmac_system_locale
= mac_get_system_locale ();
4997 /* Fetch the pathname of the application bundle as a C string into
4998 app_bundle_pathname. */
5000 bundle
= CFBundleGetMainBundle ();
5001 if (!bundle
|| CFBundleGetIdentifier (bundle
) == NULL
)
5003 /* We could not find the bundle identifier. For now, prevent
5004 the fatal error by bringing it up in the terminal. */
5005 inhibit_window_system
= 1;
5009 bundleURL
= CFBundleCopyBundleURL (bundle
);
5013 cf_app_bundle_pathname
= CFURLCopyFileSystemPath (bundleURL
,
5014 kCFURLPOSIXPathStyle
);
5015 app_bundle_pathname_len
= CFStringGetLength (cf_app_bundle_pathname
);
5016 app_bundle_pathname
= (char *) alloca (app_bundle_pathname_len
+ 1);
5018 if (!CFStringGetCString (cf_app_bundle_pathname
,
5019 app_bundle_pathname
,
5020 app_bundle_pathname_len
+ 1,
5021 kCFStringEncodingISOLatin1
))
5023 CFRelease (cf_app_bundle_pathname
);
5027 CFRelease (cf_app_bundle_pathname
);
5029 /* P should have sufficient room for the pathname of the bundle plus
5030 the subpath in it leading to the respective directories. Q
5031 should have three times that much room because EMACSLOADPATH can
5032 have the value "<path to lisp dir>:<path to leim dir>:<path to
5034 p
= (char *) alloca (app_bundle_pathname_len
+ 50);
5035 q
= (char *) alloca (3 * app_bundle_pathname_len
+ 150);
5036 if (!getenv ("EMACSLOADPATH"))
5040 strcpy (p
, app_bundle_pathname
);
5041 strcat (p
, "/Contents/Resources/lisp");
5042 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
5045 strcpy (p
, app_bundle_pathname
);
5046 strcat (p
, "/Contents/Resources/leim");
5047 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
5054 strcpy (p
, app_bundle_pathname
);
5055 strcat (p
, "/Contents/Resources/site-lisp");
5056 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
5064 setenv ("EMACSLOADPATH", q
, 1);
5067 if (!getenv ("EMACSPATH"))
5071 strcpy (p
, app_bundle_pathname
);
5072 strcat (p
, "/Contents/MacOS/libexec");
5073 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
5076 strcpy (p
, app_bundle_pathname
);
5077 strcat (p
, "/Contents/MacOS/bin");
5078 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
5086 setenv ("EMACSPATH", q
, 1);
5089 if (!getenv ("EMACSDATA"))
5091 strcpy (p
, app_bundle_pathname
);
5092 strcat (p
, "/Contents/Resources/etc");
5093 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
5094 setenv ("EMACSDATA", p
, 1);
5097 if (!getenv ("EMACSDOC"))
5099 strcpy (p
, app_bundle_pathname
);
5100 strcat (p
, "/Contents/Resources/etc");
5101 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
5102 setenv ("EMACSDOC", p
, 1);
5105 if (!getenv ("INFOPATH"))
5107 strcpy (p
, app_bundle_pathname
);
5108 strcat (p
, "/Contents/Resources/info");
5109 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
5110 setenv ("INFOPATH", p
, 1);
5113 #endif /* MAC_OSX */
5119 Qundecoded_file_name
= intern ("undecoded-file-name");
5120 staticpro (&Qundecoded_file_name
);
5122 #if TARGET_API_MAC_CARBON
5123 Qstring
= intern ("string"); staticpro (&Qstring
);
5124 Qnumber
= intern ("number"); staticpro (&Qnumber
);
5125 Qboolean
= intern ("boolean"); staticpro (&Qboolean
);
5126 Qdate
= intern ("date"); staticpro (&Qdate
);
5127 Qdata
= intern ("data"); staticpro (&Qdata
);
5128 Qarray
= intern ("array"); staticpro (&Qarray
);
5129 Qdictionary
= intern ("dictionary"); staticpro (&Qdictionary
);
5131 Qxml
= intern ("xml");
5134 Qmime_charset
= intern ("mime-charset");
5135 staticpro (&Qmime_charset
);
5137 QNFD
= intern ("NFD"); staticpro (&QNFD
);
5138 QNFKD
= intern ("NFKD"); staticpro (&QNFKD
);
5139 QNFC
= intern ("NFC"); staticpro (&QNFC
);
5140 QNFKC
= intern ("NFKC"); staticpro (&QNFKC
);
5141 QHFS_plus_D
= intern ("HFS+D"); staticpro (&QHFS_plus_D
);
5142 QHFS_plus_C
= intern ("HFS+C"); staticpro (&QHFS_plus_C
);
5145 defsubr (&Smac_coerce_ae_data
);
5146 #if TARGET_API_MAC_CARBON
5147 defsubr (&Smac_get_preference
);
5148 defsubr (&Smac_code_convert_string
);
5150 defsubr (&Smac_clear_font_name_table
);
5152 defsubr (&Smac_set_file_creator
);
5153 defsubr (&Smac_set_file_type
);
5154 defsubr (&Smac_get_file_creator
);
5155 defsubr (&Smac_get_file_type
);
5156 defsubr (&Sdo_applescript
);
5157 defsubr (&Smac_file_name_to_posix
);
5158 defsubr (&Sposix_file_name_to_mac
);
5160 DEFVAR_INT ("mac-system-script-code", &mac_system_script_code
,
5161 doc
: /* The system script code. */);
5162 mac_system_script_code
= (ScriptCode
) GetScriptManagerVariable (smSysScript
);
5164 DEFVAR_LISP ("mac-system-locale", &Vmac_system_locale
,
5165 doc
: /* The system locale identifier string.
5166 This is not a POSIX locale ID, but an ICU locale ID. So encoding
5167 information is not included. */);
5168 Vmac_system_locale
= mac_get_system_locale ();
5171 /* arch-tag: 29d30c1f-0c6b-4f88-8a6d-0558d7f9dbff
5172 (do not change this comment) */