1 /* Unix emulation routines for GNU Emacs on the Mac OS.
2 Copyright (C) 2000, 2001, 2002, 2003, 2004,
3 2005 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
;
83 /* When converting from Mac to Unix pathnames, /'s in folder names are
84 converted to :'s. This function, used in copying folder names,
85 performs a strncat and converts all character a to b in the copy of
86 the string s2 appended to the end of s1. */
89 string_cat_and_replace (char *s1
, const char *s2
, int n
, char a
, char b
)
97 for (i
= 0; i
< l2
; i
++)
106 /* Convert a Mac pathname to Posix form. A Mac full pathname is one
107 that does not begin with a ':' and contains at least one ':'. A Mac
108 full pathname causes a '/' to be prepended to the Posix pathname.
109 The algorithm for the rest of the pathname is as follows:
110 For each segment between two ':',
111 if it is non-null, copy as is and then add a '/' at the end,
112 otherwise, insert a "../" into the Posix pathname.
113 Returns 1 if successful; 0 if fails. */
116 mac_to_posix_pathname (const char *mfn
, char *ufn
, int ufnbuflen
)
118 const char *p
, *q
, *pe
;
125 p
= strchr (mfn
, ':');
126 if (p
!= 0 && p
!= mfn
) /* full pathname */
133 pe
= mfn
+ strlen (mfn
);
140 { /* two consecutive ':' */
141 if (strlen (ufn
) + 3 >= ufnbuflen
)
147 if (strlen (ufn
) + (q
- p
) + 1 >= ufnbuflen
)
149 string_cat_and_replace (ufn
, p
, q
- p
, '/', ':');
156 if (strlen (ufn
) + (pe
- p
) >= ufnbuflen
)
158 string_cat_and_replace (ufn
, p
, pe
- p
, '/', ':');
159 /* no separator for last one */
168 extern char *get_temp_dir_name ();
171 /* Convert a Posix pathname to Mac form. Approximately reverse of the
172 above in algorithm. */
175 posix_to_mac_pathname (const char *ufn
, char *mfn
, int mfnbuflen
)
177 const char *p
, *q
, *pe
;
178 char expanded_pathname
[MAXPATHLEN
+1];
187 /* Check for and handle volume names. Last comparison: strangely
188 somewhere "/.emacs" is passed. A temporary fix for now. */
189 if (*p
== '/' && strchr (p
+1, '/') == NULL
&& strcmp (p
, "/.emacs") != 0)
191 if (strlen (p
) + 1 > mfnbuflen
)
198 /* expand to emacs dir found by init_emacs_passwd_dir */
199 if (strncmp (p
, "~emacs/", 7) == 0)
201 struct passwd
*pw
= getpwnam ("emacs");
203 if (strlen (pw
->pw_dir
) + strlen (p
) > MAXPATHLEN
)
205 strcpy (expanded_pathname
, pw
->pw_dir
);
206 strcat (expanded_pathname
, p
);
207 p
= expanded_pathname
;
208 /* now p points to the pathname with emacs dir prefix */
210 else if (strncmp (p
, "/tmp/", 5) == 0)
212 char *t
= get_temp_dir_name ();
214 if (strlen (t
) + strlen (p
) > MAXPATHLEN
)
216 strcpy (expanded_pathname
, t
);
217 strcat (expanded_pathname
, p
);
218 p
= expanded_pathname
;
219 /* now p points to the pathname with emacs dir prefix */
221 else if (*p
!= '/') /* relative pathname */
233 if (q
- p
== 2 && *p
== '.' && *(p
+1) == '.')
235 if (strlen (mfn
) + 1 >= mfnbuflen
)
241 if (strlen (mfn
) + (q
- p
) + 1 >= mfnbuflen
)
243 string_cat_and_replace (mfn
, p
, q
- p
, ':', '/');
250 if (strlen (mfn
) + (pe
- p
) >= mfnbuflen
)
252 string_cat_and_replace (mfn
, p
, pe
- p
, ':', '/');
261 /***********************************************************************
262 Conversion between Lisp and Core Foundation objects
263 ***********************************************************************/
265 #if TARGET_API_MAC_CARBON
266 static Lisp_Object Qstring
, Qnumber
, Qboolean
, Qdate
, Qdata
;
267 static Lisp_Object Qarray
, Qdictionary
;
268 #define DECODE_UTF_8(str) code_convert_string_norecord (str, Qutf_8, 0)
270 struct cfdict_context
273 int with_tag
, hash_bound
;
276 /* C string to CFString. */
279 cfstring_create_with_utf8_cstring (c_str
)
284 str
= CFStringCreateWithCString (NULL
, c_str
, kCFStringEncodingUTF8
);
286 /* Failed to interpret as UTF 8. Fall back on Mac Roman. */
287 str
= CFStringCreateWithCString (NULL
, c_str
, kCFStringEncodingMacRoman
);
293 /* Lisp string to CFString. */
296 cfstring_create_with_string (s
)
299 CFStringRef string
= NULL
;
301 if (STRING_MULTIBYTE (s
))
303 char *p
, *end
= SDATA (s
) + SBYTES (s
);
305 for (p
= SDATA (s
); p
< end
; p
++)
308 s
= ENCODE_UTF_8 (s
);
311 string
= CFStringCreateWithBytes (NULL
, SDATA (s
), SBYTES (s
),
312 kCFStringEncodingUTF8
, false);
316 /* Failed to interpret as UTF 8. Fall back on Mac Roman. */
317 string
= CFStringCreateWithBytes (NULL
, SDATA (s
), SBYTES (s
),
318 kCFStringEncodingMacRoman
, false);
324 /* From CFData to a lisp string. Always returns a unibyte string. */
327 cfdata_to_lisp (data
)
330 CFIndex len
= CFDataGetLength (data
);
331 Lisp_Object result
= make_uninit_string (len
);
333 CFDataGetBytes (data
, CFRangeMake (0, len
), SDATA (result
));
339 /* From CFString to a lisp string. Never returns a unibyte string
340 (even if it only contains ASCII characters).
341 This may cause GC during code conversion. */
344 cfstring_to_lisp (string
)
347 Lisp_Object result
= Qnil
;
348 const char *s
= CFStringGetCStringPtr (string
, kCFStringEncodingUTF8
);
351 result
= make_unibyte_string (s
, strlen (s
));
355 CFStringCreateExternalRepresentation (NULL
, string
,
356 kCFStringEncodingUTF8
, '?');
360 result
= cfdata_to_lisp (data
);
367 result
= DECODE_UTF_8 (result
);
368 /* This may be superfluous. Just to make sure that the result
369 is a multibyte string. */
370 result
= string_to_multibyte (result
);
377 /* CFNumber to a lisp integer or a lisp float. */
380 cfnumber_to_lisp (number
)
383 Lisp_Object result
= Qnil
;
384 #if BITS_PER_EMACS_INT > 32
386 CFNumberType emacs_int_type
= kCFNumberSInt64Type
;
389 CFNumberType emacs_int_type
= kCFNumberSInt32Type
;
393 if (CFNumberGetValue (number
, emacs_int_type
, &int_val
)
394 && !FIXNUM_OVERFLOW_P (int_val
))
395 result
= make_number (int_val
);
397 if (CFNumberGetValue (number
, kCFNumberDoubleType
, &float_val
))
398 result
= make_float (float_val
);
403 /* CFDate to a list of three integers as in a return value of
407 cfdate_to_lisp (date
)
410 static const CFGregorianDate epoch_gdate
= {1970, 1, 1, 0, 0, 0.0};
411 static CFAbsoluteTime epoch
= 0.0, sec
;
415 epoch
= CFGregorianDateGetAbsoluteTime (epoch_gdate
, NULL
);
417 sec
= CFDateGetAbsoluteTime (date
) - epoch
;
418 high
= sec
/ 65536.0;
419 low
= sec
- high
* 65536.0;
421 return list3 (make_number (high
), make_number (low
), make_number (0));
425 /* CFBoolean to a lisp symbol, `t' or `nil'. */
428 cfboolean_to_lisp (boolean
)
429 CFBooleanRef boolean
;
431 return CFBooleanGetValue (boolean
) ? Qt
: Qnil
;
435 /* Any Core Foundation object to a (lengthy) lisp string. */
438 cfobject_desc_to_lisp (object
)
441 Lisp_Object result
= Qnil
;
442 CFStringRef desc
= CFCopyDescription (object
);
446 result
= cfstring_to_lisp (desc
);
454 /* Callback functions for cfproperty_list_to_lisp. */
457 cfdictionary_add_to_list (key
, value
, context
)
462 struct cfdict_context
*cxt
= (struct cfdict_context
*)context
;
465 Fcons (Fcons (cfstring_to_lisp (key
),
466 cfproperty_list_to_lisp (value
, cxt
->with_tag
,
472 cfdictionary_puthash (key
, value
, context
)
477 Lisp_Object lisp_key
= cfstring_to_lisp (key
);
478 struct cfdict_context
*cxt
= (struct cfdict_context
*)context
;
479 struct Lisp_Hash_Table
*h
= XHASH_TABLE (*(cxt
->result
));
482 hash_lookup (h
, lisp_key
, &hash_code
);
483 hash_put (h
, lisp_key
,
484 cfproperty_list_to_lisp (value
, cxt
->with_tag
, cxt
->hash_bound
),
489 /* Convert CFPropertyList PLIST to a lisp object. If WITH_TAG is
490 non-zero, a symbol that represents the type of the original Core
491 Foundation object is prepended. HASH_BOUND specifies which kinds
492 of the lisp objects, alists or hash tables, are used as the targets
493 of the conversion from CFDictionary. If HASH_BOUND is negative,
494 always generate alists. If HASH_BOUND >= 0, generate an alist if
495 the number of keys in the dictionary is smaller than HASH_BOUND,
496 and a hash table otherwise. */
499 cfproperty_list_to_lisp (plist
, with_tag
, hash_bound
)
500 CFPropertyListRef plist
;
501 int with_tag
, hash_bound
;
503 CFTypeID type_id
= CFGetTypeID (plist
);
504 Lisp_Object tag
= Qnil
, result
= Qnil
;
505 struct gcpro gcpro1
, gcpro2
;
507 GCPRO2 (tag
, result
);
509 if (type_id
== CFStringGetTypeID ())
512 result
= cfstring_to_lisp (plist
);
514 else if (type_id
== CFNumberGetTypeID ())
517 result
= cfnumber_to_lisp (plist
);
519 else if (type_id
== CFBooleanGetTypeID ())
522 result
= cfboolean_to_lisp (plist
);
524 else if (type_id
== CFDateGetTypeID ())
527 result
= cfdate_to_lisp (plist
);
529 else if (type_id
== CFDataGetTypeID ())
532 result
= cfdata_to_lisp (plist
);
534 else if (type_id
== CFArrayGetTypeID ())
536 CFIndex index
, count
= CFArrayGetCount (plist
);
539 result
= Fmake_vector (make_number (count
), Qnil
);
540 for (index
= 0; index
< count
; index
++)
541 XVECTOR (result
)->contents
[index
] =
542 cfproperty_list_to_lisp (CFArrayGetValueAtIndex (plist
, index
),
543 with_tag
, hash_bound
);
545 else if (type_id
== CFDictionaryGetTypeID ())
547 struct cfdict_context context
;
548 CFIndex count
= CFDictionaryGetCount (plist
);
551 context
.result
= &result
;
552 context
.with_tag
= with_tag
;
553 context
.hash_bound
= hash_bound
;
554 if (hash_bound
< 0 || count
< hash_bound
)
557 CFDictionaryApplyFunction (plist
, cfdictionary_add_to_list
,
562 result
= make_hash_table (Qequal
,
564 make_float (DEFAULT_REHASH_SIZE
),
565 make_float (DEFAULT_REHASH_THRESHOLD
),
567 CFDictionaryApplyFunction (plist
, cfdictionary_puthash
,
577 result
= Fcons (tag
, result
);
584 /***********************************************************************
585 Emulation of the X Resource Manager
586 ***********************************************************************/
588 /* Parser functions for resource lines. Each function takes an
589 address of a variable whose value points to the head of a string.
590 The value will be advanced so that it points to the next character
591 of the parsed part when the function returns.
593 A resource name such as "Emacs*font" is parsed into a non-empty
594 list called `quarks'. Each element is either a Lisp string that
595 represents a concrete component, a Lisp symbol LOOSE_BINDING
596 (actually Qlambda) that represents any number (>=0) of intervening
597 components, or a Lisp symbol SINGLE_COMPONENT (actually Qquote)
598 that represents as any single component. */
602 #define LOOSE_BINDING Qlambda /* '*' ("L"oose) */
603 #define SINGLE_COMPONENT Qquote /* '?' ("Q"uestion) */
609 /* WhiteSpace = {<space> | <horizontal tab>} */
610 while (*P
== ' ' || *P
== '\t')
618 /* Comment = "!" {<any character except null or newline>} */
631 /* Don't interpret filename. Just skip until the newline. */
633 parse_include_file (p
)
636 /* IncludeFile = "#" WhiteSpace "include" WhiteSpace FileName WhiteSpace */
653 /* Binding = "." | "*" */
654 if (*P
== '.' || *P
== '*')
658 while (*P
== '.' || *P
== '*')
671 /* Component = "?" | ComponentName
672 ComponentName = NameChar {NameChar}
673 NameChar = "a"-"z" | "A"-"Z" | "0"-"9" | "_" | "-" */
677 return SINGLE_COMPONENT
;
679 else if (isalnum (*P
) || *P
== '_' || *P
== '-')
683 while (isalnum (*P
) || *P
== '_' || *P
== '-')
686 return make_unibyte_string (start
, P
- start
);
693 parse_resource_name (p
)
696 Lisp_Object result
= Qnil
, component
;
699 /* ResourceName = [Binding] {Component Binding} ComponentName */
700 if (parse_binding (p
) == '*')
701 result
= Fcons (LOOSE_BINDING
, result
);
703 component
= parse_component (p
);
704 if (NILP (component
))
707 result
= Fcons (component
, result
);
708 while ((binding
= parse_binding (p
)) != '\0')
711 result
= Fcons (LOOSE_BINDING
, result
);
712 component
= parse_component (p
);
713 if (NILP (component
))
716 result
= Fcons (component
, result
);
719 /* The final component should not be '?'. */
720 if (EQ (component
, SINGLE_COMPONENT
))
723 return Fnreverse (result
);
731 Lisp_Object seq
= Qnil
, result
;
732 int buf_len
, total_len
= 0, len
, continue_p
;
734 q
= strchr (P
, '\n');
735 buf_len
= q
? q
- P
: strlen (P
);
736 buf
= xmalloc (buf_len
);
765 else if ('0' <= P
[0] && P
[0] <= '7'
766 && '0' <= P
[1] && P
[1] <= '7'
767 && '0' <= P
[2] && P
[2] <= '7')
769 *q
++ = (P
[0] - '0' << 6) + (P
[1] - '0' << 3) + (P
[2] - '0');
779 seq
= Fcons (make_unibyte_string (buf
, len
), seq
);
784 q
= strchr (P
, '\n');
785 len
= q
? q
- P
: strlen (P
);
790 buf
= xmalloc (buf_len
);
798 if (SBYTES (XCAR (seq
)) == total_len
)
799 return make_string (SDATA (XCAR (seq
)), total_len
);
802 buf
= xmalloc (total_len
);
804 for (; CONSP (seq
); seq
= XCDR (seq
))
806 len
= SBYTES (XCAR (seq
));
808 memcpy (q
, SDATA (XCAR (seq
)), len
);
810 result
= make_string (buf
, total_len
);
817 parse_resource_line (p
)
820 Lisp_Object quarks
, value
;
822 /* ResourceLine = Comment | IncludeFile | ResourceSpec | <empty line> */
823 if (parse_comment (p
) || parse_include_file (p
))
826 /* ResourceSpec = WhiteSpace ResourceName WhiteSpace ":" WhiteSpace Value */
827 skip_white_space (p
);
828 quarks
= parse_resource_name (p
);
831 skip_white_space (p
);
835 skip_white_space (p
);
836 value
= parse_value (p
);
837 return Fcons (quarks
, value
);
840 /* Skip the remaining data as a dummy value. */
847 /* Equivalents of X Resource Manager functions.
849 An X Resource Database acts as a collection of resource names and
850 associated values. It is implemented as a trie on quarks. Namely,
851 each edge is labeled by either a string, LOOSE_BINDING, or
852 SINGLE_COMPONENT. Each node has a node id, which is a unique
853 nonnegative integer, and the root node id is 0. A database is
854 implemented as a hash table that maps a pair (SRC-NODE-ID .
855 EDGE-LABEL) to DEST-NODE-ID. It also holds a maximum node id used
856 in the table as a value for HASHKEY_MAX_NID. A value associated to
857 a node is recorded as a value for the node id. */
859 #define HASHKEY_MAX_NID (make_number (0))
862 xrm_create_database ()
864 XrmDatabase database
;
866 database
= make_hash_table (Qequal
, make_number (DEFAULT_HASH_SIZE
),
867 make_float (DEFAULT_REHASH_SIZE
),
868 make_float (DEFAULT_REHASH_THRESHOLD
),
870 Fputhash (HASHKEY_MAX_NID
, make_number (0), database
);
876 xrm_q_put_resource (database
, quarks
, value
)
877 XrmDatabase database
;
878 Lisp_Object quarks
, value
;
880 struct Lisp_Hash_Table
*h
= XHASH_TABLE (database
);
883 Lisp_Object node_id
, key
;
885 max_nid
= XINT (Fgethash (HASHKEY_MAX_NID
, database
, Qnil
));
887 XSETINT (node_id
, 0);
888 for (; CONSP (quarks
); quarks
= XCDR (quarks
))
890 key
= Fcons (node_id
, XCAR (quarks
));
891 i
= hash_lookup (h
, key
, &hash_code
);
895 XSETINT (node_id
, max_nid
);
896 hash_put (h
, key
, node_id
, hash_code
);
899 node_id
= HASH_VALUE (h
, i
);
901 Fputhash (node_id
, value
, database
);
903 Fputhash (HASHKEY_MAX_NID
, make_number (max_nid
), database
);
906 /* Merge multiple resource entries specified by DATA into a resource
907 database DATABASE. DATA points to the head of a null-terminated
908 string consisting of multiple resource lines. It's like a
909 combination of XrmGetStringDatabase and XrmMergeDatabases. */
912 xrm_merge_string_database (database
, data
)
913 XrmDatabase database
;
916 Lisp_Object quarks_value
;
920 quarks_value
= parse_resource_line (&data
);
921 if (!NILP (quarks_value
))
922 xrm_q_put_resource (database
,
923 XCAR (quarks_value
), XCDR (quarks_value
));
928 xrm_q_get_resource_1 (database
, node_id
, quark_name
, quark_class
)
929 XrmDatabase database
;
930 Lisp_Object node_id
, quark_name
, quark_class
;
932 struct Lisp_Hash_Table
*h
= XHASH_TABLE (database
);
933 Lisp_Object key
, labels
[3], value
;
936 if (!CONSP (quark_name
))
937 return Fgethash (node_id
, database
, Qnil
);
939 /* First, try tight bindings */
940 labels
[0] = XCAR (quark_name
);
941 labels
[1] = XCAR (quark_class
);
942 labels
[2] = SINGLE_COMPONENT
;
944 key
= Fcons (node_id
, Qnil
);
945 for (k
= 0; k
< sizeof (labels
) / sizeof (*labels
); k
++)
947 XSETCDR (key
, labels
[k
]);
948 i
= hash_lookup (h
, key
, NULL
);
951 value
= xrm_q_get_resource_1 (database
, HASH_VALUE (h
, i
),
952 XCDR (quark_name
), XCDR (quark_class
));
958 /* Then, try loose bindings */
959 XSETCDR (key
, LOOSE_BINDING
);
960 i
= hash_lookup (h
, key
, NULL
);
963 value
= xrm_q_get_resource_1 (database
, HASH_VALUE (h
, i
),
964 quark_name
, quark_class
);
968 return xrm_q_get_resource_1 (database
, node_id
,
969 XCDR (quark_name
), XCDR (quark_class
));
976 xrm_q_get_resource (database
, quark_name
, quark_class
)
977 XrmDatabase database
;
978 Lisp_Object quark_name
, quark_class
;
980 return xrm_q_get_resource_1 (database
, make_number (0),
981 quark_name
, quark_class
);
984 /* Retrieve a resource value for the specified NAME and CLASS from the
985 resource database DATABASE. It corresponds to XrmGetResource. */
988 xrm_get_resource (database
, name
, class)
989 XrmDatabase database
;
992 Lisp_Object quark_name
, quark_class
, tmp
;
995 quark_name
= parse_resource_name (&name
);
998 for (tmp
= quark_name
, nn
= 0; CONSP (tmp
); tmp
= XCDR (tmp
), nn
++)
999 if (!STRINGP (XCAR (tmp
)))
1002 quark_class
= parse_resource_name (&class);
1005 for (tmp
= quark_class
, nc
= 0; CONSP (tmp
); tmp
= XCDR (tmp
), nc
++)
1006 if (!STRINGP (XCAR (tmp
)))
1012 return xrm_q_get_resource (database
, quark_name
, quark_class
);
1015 #if TARGET_API_MAC_CARBON
1017 xrm_cfproperty_list_to_value (plist
)
1018 CFPropertyListRef plist
;
1020 CFTypeID type_id
= CFGetTypeID (plist
);
1022 if (type_id
== CFStringGetTypeID ())
1023 return cfstring_to_lisp (plist
);
1024 else if (type_id
== CFNumberGetTypeID ())
1027 Lisp_Object result
= Qnil
;
1029 string
= CFStringCreateWithFormat (NULL
, NULL
, CFSTR ("%@"), plist
);
1032 result
= cfstring_to_lisp (string
);
1037 else if (type_id
== CFBooleanGetTypeID ())
1038 return build_string (CFBooleanGetValue (plist
) ? "true" : "false");
1039 else if (type_id
== CFDataGetTypeID ())
1040 return cfdata_to_lisp (plist
);
1046 /* Create a new resource database from the preferences for the
1047 application APPLICATION. APPLICATION is either a string that
1048 specifies an application ID, or NULL that represents the current
1052 xrm_get_preference_database (application
)
1055 #if TARGET_API_MAC_CARBON
1056 CFStringRef app_id
, *keys
, user_doms
[2], host_doms
[2];
1057 CFMutableSetRef key_set
= NULL
;
1058 CFArrayRef key_array
;
1059 CFIndex index
, count
;
1061 XrmDatabase database
;
1062 Lisp_Object quarks
= Qnil
, value
= Qnil
;
1063 CFPropertyListRef plist
;
1065 struct gcpro gcpro1
, gcpro2
, gcpro3
;
1067 user_doms
[0] = kCFPreferencesCurrentUser
;
1068 user_doms
[1] = kCFPreferencesAnyUser
;
1069 host_doms
[0] = kCFPreferencesCurrentHost
;
1070 host_doms
[1] = kCFPreferencesAnyHost
;
1072 database
= xrm_create_database ();
1074 GCPRO3 (database
, quarks
, value
);
1078 app_id
= kCFPreferencesCurrentApplication
;
1081 app_id
= cfstring_create_with_utf8_cstring (application
);
1086 key_set
= CFSetCreateMutable (NULL
, 0, &kCFCopyStringSetCallBacks
);
1087 if (key_set
== NULL
)
1089 for (iu
= 0; iu
< sizeof (user_doms
) / sizeof (*user_doms
) ; iu
++)
1090 for (ih
= 0; ih
< sizeof (host_doms
) / sizeof (*host_doms
); ih
++)
1092 key_array
= CFPreferencesCopyKeyList (app_id
, user_doms
[iu
],
1096 count
= CFArrayGetCount (key_array
);
1097 for (index
= 0; index
< count
; index
++)
1098 CFSetAddValue (key_set
,
1099 CFArrayGetValueAtIndex (key_array
, index
));
1100 CFRelease (key_array
);
1104 count
= CFSetGetCount (key_set
);
1105 keys
= xmalloc (sizeof (CFStringRef
) * count
);
1108 CFSetGetValues (key_set
, (const void **)keys
);
1109 for (index
= 0; index
< count
; index
++)
1111 res_name
= SDATA (cfstring_to_lisp (keys
[index
]));
1112 quarks
= parse_resource_name (&res_name
);
1113 if (!(NILP (quarks
) || *res_name
))
1115 plist
= CFPreferencesCopyAppValue (keys
[index
], app_id
);
1116 value
= xrm_cfproperty_list_to_value (plist
);
1119 xrm_q_put_resource (database
, quarks
, value
);
1126 CFRelease (key_set
);
1135 return xrm_create_database ();
1142 /* The following functions with "sys_" prefix are stubs to Unix
1143 functions that have already been implemented by CW or MPW. The
1144 calls to them in Emacs source course are #define'd to call the sys_
1145 versions by the header files s-mac.h. In these stubs pathnames are
1146 converted between their Unix and Mac forms. */
1149 /* Unix epoch is Jan 1, 1970 while Mac epoch is Jan 1, 1904: 66 years
1150 + 17 leap days. These are for adjusting time values returned by
1151 MacOS Toolbox functions. */
1153 #define MAC_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
1156 #if __MSL__ < 0x6000
1157 /* CW Pro 5 epoch is Jan 1, 1900 (aaarghhhhh!); remember, 1900 is not
1158 a leap year! This is for adjusting time_t values returned by MSL
1160 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 70 + 17) * 24 * 60 * 60)
1161 #else /* __MSL__ >= 0x6000 */
1162 /* CW changes Pro 6 to follow Unix! */
1163 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
1164 #endif /* __MSL__ >= 0x6000 */
1166 /* MPW library functions follow Unix (confused?). */
1167 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
1168 #else /* not __MRC__ */
1170 #endif /* not __MRC__ */
1173 /* Define our own stat function for both MrC and CW. The reason for
1174 doing this: "stat" is both the name of a struct and function name:
1175 can't use the same trick like that for sys_open, sys_close, etc. to
1176 redirect Emacs's calls to our own version that converts Unix style
1177 filenames to Mac style filename because all sorts of compilation
1178 errors will be generated if stat is #define'd to be sys_stat. */
1181 stat_noalias (const char *path
, struct stat
*buf
)
1183 char mac_pathname
[MAXPATHLEN
+1];
1186 if (posix_to_mac_pathname (path
, mac_pathname
, MAXPATHLEN
+1) == 0)
1189 c2pstr (mac_pathname
);
1190 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
1191 cipb
.hFileInfo
.ioVRefNum
= 0;
1192 cipb
.hFileInfo
.ioDirID
= 0;
1193 cipb
.hFileInfo
.ioFDirIndex
= 0;
1194 /* set to 0 to get information about specific dir or file */
1196 errno
= PBGetCatInfo (&cipb
, false);
1197 if (errno
== -43) /* -43: fnfErr defined in Errors.h */
1202 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* bit 4 = 1 for directories */
1204 buf
->st_mode
= S_IFDIR
| S_IREAD
| S_IEXEC
;
1206 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x1))
1207 buf
->st_mode
|= S_IWRITE
; /* bit 1 = 1 for locked files/directories */
1208 buf
->st_ino
= cipb
.dirInfo
.ioDrDirID
;
1209 buf
->st_dev
= cipb
.dirInfo
.ioVRefNum
;
1210 buf
->st_size
= cipb
.dirInfo
.ioDrNmFls
;
1211 /* size of dir = number of files and dirs */
1214 = cipb
.dirInfo
.ioDrMdDat
- MAC_UNIX_EPOCH_DIFF
;
1215 buf
->st_ctime
= cipb
.dirInfo
.ioDrCrDat
- MAC_UNIX_EPOCH_DIFF
;
1219 buf
->st_mode
= S_IFREG
| S_IREAD
;
1220 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x1))
1221 buf
->st_mode
|= S_IWRITE
; /* bit 1 = 1 for locked files/directories */
1222 if (cipb
.hFileInfo
.ioFlFndrInfo
.fdType
== 'APPL')
1223 buf
->st_mode
|= S_IEXEC
;
1224 buf
->st_ino
= cipb
.hFileInfo
.ioDirID
;
1225 buf
->st_dev
= cipb
.hFileInfo
.ioVRefNum
;
1226 buf
->st_size
= cipb
.hFileInfo
.ioFlLgLen
;
1229 = cipb
.hFileInfo
.ioFlMdDat
- MAC_UNIX_EPOCH_DIFF
;
1230 buf
->st_ctime
= cipb
.hFileInfo
.ioFlCrDat
- MAC_UNIX_EPOCH_DIFF
;
1233 if (cipb
.hFileInfo
.ioFlFndrInfo
.fdFlags
& 0x8000)
1235 /* identify alias files as symlinks */
1236 buf
->st_mode
&= ~S_IFREG
;
1237 buf
->st_mode
|= S_IFLNK
;
1241 buf
->st_uid
= getuid ();
1242 buf
->st_gid
= getgid ();
1250 lstat (const char *path
, struct stat
*buf
)
1253 char true_pathname
[MAXPATHLEN
+1];
1255 /* Try looking for the file without resolving aliases first. */
1256 if ((result
= stat_noalias (path
, buf
)) >= 0)
1259 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
1262 return stat_noalias (true_pathname
, buf
);
1267 stat (const char *path
, struct stat
*sb
)
1270 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
1273 if ((result
= stat_noalias (path
, sb
)) >= 0 &&
1274 ! (sb
->st_mode
& S_IFLNK
))
1277 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
1280 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
1283 fully_resolved_name
[len
] = '\0';
1284 /* in fact our readlink terminates strings */
1285 return lstat (fully_resolved_name
, sb
);
1288 return lstat (true_pathname
, sb
);
1293 /* CW defines fstat in stat.mac.c while MPW does not provide this
1294 function. Without the information of how to get from a file
1295 descriptor in MPW StdCLib to a Mac OS file spec, it should be hard
1296 to implement this function. Fortunately, there is only one place
1297 where this function is called in our configuration: in fileio.c,
1298 where only the st_dev and st_ino fields are used to determine
1299 whether two fildes point to different i-nodes to prevent copying
1300 a file onto itself equal. What we have here probably needs
1304 fstat (int fildes
, struct stat
*buf
)
1307 buf
->st_ino
= fildes
;
1308 buf
->st_mode
= S_IFREG
; /* added by T.I. for the copy-file */
1309 return 0; /* success */
1311 #endif /* __MRC__ */
1315 mkdir (const char *dirname
, int mode
)
1317 #pragma unused(mode)
1320 char true_pathname
[MAXPATHLEN
+1], mac_pathname
[MAXPATHLEN
+1];
1322 if (find_true_pathname (dirname
, true_pathname
, MAXPATHLEN
+1) == -1)
1325 if (posix_to_mac_pathname (true_pathname
, mac_pathname
, MAXPATHLEN
+1) == 0)
1328 c2pstr (mac_pathname
);
1329 hfpb
.ioNamePtr
= mac_pathname
;
1330 hfpb
.ioVRefNum
= 0; /* ignored unless name is invalid */
1331 hfpb
.ioDirID
= 0; /* parent is the root */
1333 errno
= PBDirCreate ((HParmBlkPtr
) &hfpb
, false);
1334 /* just return the Mac OSErr code for now */
1335 return errno
== noErr
? 0 : -1;
1340 sys_rmdir (const char *dirname
)
1343 char mac_pathname
[MAXPATHLEN
+1];
1345 if (posix_to_mac_pathname (dirname
, mac_pathname
, MAXPATHLEN
+1) == 0)
1348 c2pstr (mac_pathname
);
1349 hfpb
.ioNamePtr
= mac_pathname
;
1350 hfpb
.ioVRefNum
= 0; /* ignored unless name is invalid */
1351 hfpb
.ioDirID
= 0; /* parent is the root */
1353 errno
= PBHDelete ((HParmBlkPtr
) &hfpb
, false);
1354 return errno
== noErr
? 0 : -1;
1359 /* No implementation yet. */
1361 execvp (const char *path
, ...)
1365 #endif /* __MRC__ */
1369 utime (const char *path
, const struct utimbuf
*times
)
1371 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
1373 char mac_pathname
[MAXPATHLEN
+1];
1376 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
1379 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
1381 fully_resolved_name
[len
] = '\0';
1383 strcpy (fully_resolved_name
, true_pathname
);
1385 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
1388 c2pstr (mac_pathname
);
1389 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
1390 cipb
.hFileInfo
.ioVRefNum
= 0;
1391 cipb
.hFileInfo
.ioDirID
= 0;
1392 cipb
.hFileInfo
.ioFDirIndex
= 0;
1393 /* set to 0 to get information about specific dir or file */
1395 errno
= PBGetCatInfo (&cipb
, false);
1399 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* bit 4 = 1 for directories */
1402 cipb
.dirInfo
.ioDrMdDat
= times
->modtime
+ MAC_UNIX_EPOCH_DIFF
;
1404 GetDateTime (&cipb
.dirInfo
.ioDrMdDat
);
1409 cipb
.hFileInfo
.ioFlMdDat
= times
->modtime
+ MAC_UNIX_EPOCH_DIFF
;
1411 GetDateTime (&cipb
.hFileInfo
.ioFlMdDat
);
1414 errno
= PBSetCatInfo (&cipb
, false);
1415 return errno
== noErr
? 0 : -1;
1429 /* Like stat, but test for access mode in hfpb.ioFlAttrib */
1431 access (const char *path
, int mode
)
1433 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
1435 char mac_pathname
[MAXPATHLEN
+1];
1438 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
1441 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
1443 fully_resolved_name
[len
] = '\0';
1445 strcpy (fully_resolved_name
, true_pathname
);
1447 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
1450 c2pstr (mac_pathname
);
1451 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
1452 cipb
.hFileInfo
.ioVRefNum
= 0;
1453 cipb
.hFileInfo
.ioDirID
= 0;
1454 cipb
.hFileInfo
.ioFDirIndex
= 0;
1455 /* set to 0 to get information about specific dir or file */
1457 errno
= PBGetCatInfo (&cipb
, false);
1461 if (mode
== F_OK
) /* got this far, file exists */
1465 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* path refers to a directory */
1469 if (cipb
.hFileInfo
.ioFlFndrInfo
.fdType
== 'APPL')
1476 return (cipb
.hFileInfo
.ioFlAttrib
& 0x1) ? -1 : 0;
1477 /* don't allow if lock bit is on */
1483 #define DEV_NULL_FD 0x10000
1487 sys_open (const char *path
, int oflag
)
1489 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
1491 char mac_pathname
[MAXPATHLEN
+1];
1493 if (strcmp (path
, "/dev/null") == 0)
1494 return DEV_NULL_FD
; /* some bogus fd to be ignored in write */
1496 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
1499 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
1501 fully_resolved_name
[len
] = '\0';
1503 strcpy (fully_resolved_name
, true_pathname
);
1505 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
1510 int res
= open (mac_pathname
, oflag
);
1511 /* if (oflag == O_WRONLY || oflag == O_RDWR) */
1512 if (oflag
& O_CREAT
)
1513 fsetfileinfo (mac_pathname
, 'EMAx', 'TEXT');
1515 #else /* not __MRC__ */
1516 return open (mac_pathname
, oflag
);
1517 #endif /* not __MRC__ */
1524 sys_creat (const char *path
, mode_t mode
)
1526 char true_pathname
[MAXPATHLEN
+1];
1528 char mac_pathname
[MAXPATHLEN
+1];
1530 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
1533 if (!posix_to_mac_pathname (true_pathname
, mac_pathname
, MAXPATHLEN
+1))
1538 int result
= creat (mac_pathname
);
1539 fsetfileinfo (mac_pathname
, 'EMAx', 'TEXT');
1541 #else /* not __MRC__ */
1542 return creat (mac_pathname
, mode
);
1543 #endif /* not __MRC__ */
1550 sys_unlink (const char *path
)
1552 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
1554 char mac_pathname
[MAXPATHLEN
+1];
1556 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
1559 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
1561 fully_resolved_name
[len
] = '\0';
1563 strcpy (fully_resolved_name
, true_pathname
);
1565 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
1568 return unlink (mac_pathname
);
1574 sys_read (int fildes
, char *buf
, int count
)
1576 if (fildes
== 0) /* this should not be used for console input */
1579 #if __MSL__ >= 0x6000
1580 return _read (fildes
, buf
, count
);
1582 return read (fildes
, buf
, count
);
1589 sys_write (int fildes
, const char *buf
, int count
)
1591 if (fildes
== DEV_NULL_FD
)
1594 #if __MSL__ >= 0x6000
1595 return _write (fildes
, buf
, count
);
1597 return write (fildes
, buf
, count
);
1604 sys_rename (const char * old_name
, const char * new_name
)
1606 char true_old_pathname
[MAXPATHLEN
+1], true_new_pathname
[MAXPATHLEN
+1];
1607 char fully_resolved_old_name
[MAXPATHLEN
+1];
1609 char mac_old_name
[MAXPATHLEN
+1], mac_new_name
[MAXPATHLEN
+1];
1611 if (find_true_pathname (old_name
, true_old_pathname
, MAXPATHLEN
+1) == -1)
1614 len
= readlink (true_old_pathname
, fully_resolved_old_name
, MAXPATHLEN
);
1616 fully_resolved_old_name
[len
] = '\0';
1618 strcpy (fully_resolved_old_name
, true_old_pathname
);
1620 if (find_true_pathname (new_name
, true_new_pathname
, MAXPATHLEN
+1) == -1)
1623 if (strcmp (fully_resolved_old_name
, true_new_pathname
) == 0)
1626 if (!posix_to_mac_pathname (fully_resolved_old_name
,
1631 if (!posix_to_mac_pathname(true_new_pathname
, mac_new_name
, MAXPATHLEN
+1))
1634 /* If a file with new_name already exists, rename deletes the old
1635 file in Unix. CW version fails in these situation. So we add a
1636 call to unlink here. */
1637 (void) unlink (mac_new_name
);
1639 return rename (mac_old_name
, mac_new_name
);
1644 extern FILE *fopen (const char *name
, const char *mode
);
1646 sys_fopen (const char *name
, const char *mode
)
1648 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
1650 char mac_pathname
[MAXPATHLEN
+1];
1652 if (find_true_pathname (name
, true_pathname
, MAXPATHLEN
+1) == -1)
1655 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
1657 fully_resolved_name
[len
] = '\0';
1659 strcpy (fully_resolved_name
, true_pathname
);
1661 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
1666 if (mode
[0] == 'w' || mode
[0] == 'a')
1667 fsetfileinfo (mac_pathname
, 'EMAx', 'TEXT');
1668 #endif /* not __MRC__ */
1669 return fopen (mac_pathname
, mode
);
1674 #include "keyboard.h"
1675 extern Boolean
mac_wait_next_event (EventRecord
*, UInt32
, Boolean
);
1678 select (n
, rfds
, wfds
, efds
, timeout
)
1683 struct timeval
*timeout
;
1686 #if TARGET_API_MAC_CARBON
1687 EventTimeout timeout_sec
=
1689 ? (EMACS_SECS (*timeout
) * kEventDurationSecond
1690 + EMACS_USECS (*timeout
) * kEventDurationMicrosecond
)
1691 : kEventDurationForever
);
1694 err
= ReceiveNextEvent (0, NULL
, timeout_sec
, kEventLeaveInQueue
, NULL
);
1696 #else /* not TARGET_API_MAC_CARBON */
1698 UInt32 sleep_time
= EMACS_SECS (*timeout
) * 60 +
1699 ((EMACS_USECS (*timeout
) * 60) / 1000000);
1701 /* Can only handle wait for keyboard input. */
1702 if (n
> 1 || wfds
|| efds
)
1705 /* Also return true if an event other than a keyDown has occurred.
1706 This causes kbd_buffer_get_event in keyboard.c to call
1707 read_avail_input which in turn calls XTread_socket to poll for
1708 these events. Otherwise these never get processed except but a
1709 very slow poll timer. */
1710 if (mac_wait_next_event (&e
, sleep_time
, false))
1713 err
= -9875; /* eventLoopTimedOutErr */
1714 #endif /* not TARGET_API_MAC_CARBON */
1716 if (FD_ISSET (0, rfds
))
1727 if (input_polling_used ())
1729 /* It could be confusing if a real alarm arrives while
1730 processing the fake one. Turn it off and let the
1731 handler reset it. */
1732 extern void poll_for_input_1
P_ ((void));
1733 int old_poll_suppress_count
= poll_suppress_count
;
1734 poll_suppress_count
= 1;
1735 poll_for_input_1 ();
1736 poll_suppress_count
= old_poll_suppress_count
;
1746 /* Simulation of SIGALRM. The stub for function signal stores the
1747 signal handler function in alarm_signal_func if a SIGALRM is
1751 #include "syssignal.h"
1753 static TMTask mac_atimer_task
;
1755 static QElemPtr mac_atimer_qlink
= (QElemPtr
) &mac_atimer_task
;
1757 static int signal_mask
= 0;
1760 __sigfun alarm_signal_func
= (__sigfun
) 0;
1762 __signal_func_ptr alarm_signal_func
= (__signal_func_ptr
) 0;
1763 #else /* not __MRC__ and not __MWERKS__ */
1765 #endif /* not __MRC__ and not __MWERKS__ */
1769 extern __sigfun
signal (int signal
, __sigfun signal_func
);
1771 sys_signal (int signal_num
, __sigfun signal_func
)
1773 extern __signal_func_ptr
signal (int signal
, __signal_func_ptr signal_func
);
1775 sys_signal (int signal_num
, __signal_func_ptr signal_func
)
1776 #else /* not __MRC__ and not __MWERKS__ */
1778 #endif /* not __MRC__ and not __MWERKS__ */
1780 if (signal_num
!= SIGALRM
)
1781 return signal (signal_num
, signal_func
);
1785 __sigfun old_signal_func
;
1787 __signal_func_ptr old_signal_func
;
1791 old_signal_func
= alarm_signal_func
;
1792 alarm_signal_func
= signal_func
;
1793 return old_signal_func
;
1799 mac_atimer_handler (qlink
)
1802 if (alarm_signal_func
)
1803 (alarm_signal_func
) (SIGALRM
);
1808 set_mac_atimer (count
)
1811 static TimerUPP mac_atimer_handlerUPP
= NULL
;
1813 if (mac_atimer_handlerUPP
== NULL
)
1814 mac_atimer_handlerUPP
= NewTimerUPP (mac_atimer_handler
);
1815 mac_atimer_task
.tmCount
= 0;
1816 mac_atimer_task
.tmAddr
= mac_atimer_handlerUPP
;
1817 mac_atimer_qlink
= (QElemPtr
) &mac_atimer_task
;
1818 InsTime (mac_atimer_qlink
);
1820 PrimeTime (mac_atimer_qlink
, count
);
1825 remove_mac_atimer (remaining_count
)
1826 long *remaining_count
;
1828 if (mac_atimer_qlink
)
1830 RmvTime (mac_atimer_qlink
);
1831 if (remaining_count
)
1832 *remaining_count
= mac_atimer_task
.tmCount
;
1833 mac_atimer_qlink
= NULL
;
1845 int old_mask
= signal_mask
;
1847 signal_mask
|= mask
;
1849 if ((old_mask
^ signal_mask
) & sigmask (SIGALRM
))
1850 remove_mac_atimer (NULL
);
1857 sigsetmask (int mask
)
1859 int old_mask
= signal_mask
;
1863 if ((old_mask
^ signal_mask
) & sigmask (SIGALRM
))
1864 if (signal_mask
& sigmask (SIGALRM
))
1865 remove_mac_atimer (NULL
);
1867 set_mac_atimer (mac_atimer_task
.tmCount
);
1876 long remaining_count
;
1878 if (remove_mac_atimer (&remaining_count
) == 0)
1880 set_mac_atimer (seconds
* 1000);
1882 return remaining_count
/ 1000;
1886 mac_atimer_task
.tmCount
= seconds
* 1000;
1894 setitimer (which
, value
, ovalue
)
1896 const struct itimerval
*value
;
1897 struct itimerval
*ovalue
;
1899 long remaining_count
;
1900 long count
= (EMACS_SECS (value
->it_value
) * 1000
1901 + (EMACS_USECS (value
->it_value
) + 999) / 1000);
1903 if (remove_mac_atimer (&remaining_count
) == 0)
1907 bzero (ovalue
, sizeof (*ovalue
));
1908 EMACS_SET_SECS_USECS (ovalue
->it_value
, remaining_count
/ 1000,
1909 (remaining_count
% 1000) * 1000);
1911 set_mac_atimer (count
);
1914 mac_atimer_task
.tmCount
= count
;
1920 /* gettimeofday should return the amount of time (in a timeval
1921 structure) since midnight today. The toolbox function Microseconds
1922 returns the number of microseconds (in a UnsignedWide value) since
1923 the machine was booted. Also making this complicated is WideAdd,
1924 WideSubtract, etc. take wide values. */
1931 static wide wall_clock_at_epoch
, clicks_at_epoch
;
1932 UnsignedWide uw_microseconds
;
1933 wide w_microseconds
;
1934 time_t sys_time (time_t *);
1936 /* If this function is called for the first time, record the number
1937 of seconds since midnight and the number of microseconds since
1938 boot at the time of this first call. */
1943 systime
= sys_time (NULL
);
1944 /* Store microseconds since midnight in wall_clock_at_epoch. */
1945 WideMultiply (systime
, 1000000L, &wall_clock_at_epoch
);
1946 Microseconds (&uw_microseconds
);
1947 /* Store microseconds since boot in clicks_at_epoch. */
1948 clicks_at_epoch
.hi
= uw_microseconds
.hi
;
1949 clicks_at_epoch
.lo
= uw_microseconds
.lo
;
1952 /* Get time since boot */
1953 Microseconds (&uw_microseconds
);
1955 /* Convert to time since midnight*/
1956 w_microseconds
.hi
= uw_microseconds
.hi
;
1957 w_microseconds
.lo
= uw_microseconds
.lo
;
1958 WideSubtract (&w_microseconds
, &clicks_at_epoch
);
1959 WideAdd (&w_microseconds
, &wall_clock_at_epoch
);
1960 tp
->tv_sec
= WideDivide (&w_microseconds
, 1000000L, &tp
->tv_usec
);
1968 sleep (unsigned int seconds
)
1970 unsigned long time_up
;
1973 time_up
= TickCount () + seconds
* 60;
1974 while (TickCount () < time_up
)
1976 /* Accept no event; just wait. by T.I. */
1977 WaitNextEvent (0, &e
, 30, NULL
);
1982 #endif /* __MRC__ */
1985 /* The time functions adjust time values according to the difference
1986 between the Unix and CW epoches. */
1989 extern struct tm
*gmtime (const time_t *);
1991 sys_gmtime (const time_t *timer
)
1993 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
1995 return gmtime (&unix_time
);
2000 extern struct tm
*localtime (const time_t *);
2002 sys_localtime (const time_t *timer
)
2004 #if __MSL__ >= 0x6000
2005 time_t unix_time
= *timer
;
2007 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
2010 return localtime (&unix_time
);
2015 extern char *ctime (const time_t *);
2017 sys_ctime (const time_t *timer
)
2019 #if __MSL__ >= 0x6000
2020 time_t unix_time
= *timer
;
2022 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
2025 return ctime (&unix_time
);
2030 extern time_t time (time_t *);
2032 sys_time (time_t *timer
)
2034 #if __MSL__ >= 0x6000
2035 time_t mac_time
= time (NULL
);
2037 time_t mac_time
= time (NULL
) - CW_OR_MPW_UNIX_EPOCH_DIFF
;
2047 /* no subprocesses, empty wait */
2057 croak (char *badfunc
)
2059 printf ("%s not yet implemented\r\n", badfunc
);
2065 mktemp (char *template)
2070 len
= strlen (template);
2072 while (k
>= 0 && template[k
] == 'X')
2075 k
++; /* make k index of first 'X' */
2079 /* Zero filled, number of digits equal to the number of X's. */
2080 sprintf (&template[k
], "%0*d", len
-k
, seqnum
++);
2089 /* Emulate getpwuid, getpwnam and others. */
2091 #define PASSWD_FIELD_SIZE 256
2093 static char my_passwd_name
[PASSWD_FIELD_SIZE
];
2094 static char my_passwd_dir
[MAXPATHLEN
+1];
2096 static struct passwd my_passwd
=
2102 static struct group my_group
=
2104 /* There are no groups on the mac, so we just return "root" as the
2110 /* Initialized by main () in macterm.c to pathname of emacs directory. */
2112 char emacs_passwd_dir
[MAXPATHLEN
+1];
2118 init_emacs_passwd_dir ()
2122 if (getwd (emacs_passwd_dir
) && getwd (my_passwd_dir
))
2124 /* Need pathname of first ancestor that begins with "emacs"
2125 since Mac emacs application is somewhere in the emacs-*
2127 int len
= strlen (emacs_passwd_dir
);
2129 /* j points to the "/" following the directory name being
2132 while (i
>= 0 && !found
)
2134 while (i
>= 0 && emacs_passwd_dir
[i
] != '/')
2136 if (emacs_passwd_dir
[i
] == '/' && i
+5 < len
)
2137 found
= (strncmp (&(emacs_passwd_dir
[i
+1]), "emacs", 5) == 0);
2139 emacs_passwd_dir
[j
+1] = '\0';
2150 /* Setting to "/" probably won't work but set it to something
2152 strcpy (emacs_passwd_dir
, "/");
2153 strcpy (my_passwd_dir
, "/");
2158 static struct passwd emacs_passwd
=
2164 static int my_passwd_inited
= 0;
2172 /* Note: my_passwd_dir initialized in int_emacs_passwd_dir to
2173 directory where Emacs was started. */
2175 owner_name
= (char **) GetResource ('STR ',-16096);
2179 BlockMove ((unsigned char *) *owner_name
,
2180 (unsigned char *) my_passwd_name
,
2182 HUnlock (owner_name
);
2183 p2cstr ((unsigned char *) my_passwd_name
);
2186 my_passwd_name
[0] = 0;
2191 getpwuid (uid_t uid
)
2193 if (!my_passwd_inited
)
2196 my_passwd_inited
= 1;
2204 getgrgid (gid_t gid
)
2211 getpwnam (const char *name
)
2213 if (strcmp (name
, "emacs") == 0)
2214 return &emacs_passwd
;
2216 if (!my_passwd_inited
)
2219 my_passwd_inited
= 1;
2226 /* The functions fork, kill, sigsetmask, sigblock, request_sigio,
2227 setpgrp, setpriority, and unrequest_sigio are defined to be empty
2248 error ("Can't spawn subshell");
2253 request_sigio (void)
2259 unrequest_sigio (void)
2274 pipe (int _fildes
[2])
2281 /* Hard and symbolic links. */
2284 symlink (const char *name1
, const char *name2
)
2292 link (const char *name1
, const char *name2
)
2298 #endif /* ! MAC_OSX */
2300 /* Determine the path name of the file specified by VREFNUM, DIRID,
2301 and NAME and place that in the buffer PATH of length
2304 path_from_vol_dir_name (char *path
, int man_path_len
, short vol_ref_num
,
2305 long dir_id
, ConstStr255Param name
)
2311 if (strlen (name
) > man_path_len
)
2314 memcpy (dir_name
, name
, name
[0]+1);
2315 memcpy (path
, name
, name
[0]+1);
2318 cipb
.dirInfo
.ioDrParID
= dir_id
;
2319 cipb
.dirInfo
.ioNamePtr
= dir_name
;
2323 cipb
.dirInfo
.ioVRefNum
= vol_ref_num
;
2324 cipb
.dirInfo
.ioFDirIndex
= -1;
2325 cipb
.dirInfo
.ioDrDirID
= cipb
.dirInfo
.ioDrParID
;
2326 /* go up to parent each time */
2328 err
= PBGetCatInfo (&cipb
, false);
2333 if (strlen (dir_name
) + strlen (path
) + 1 >= man_path_len
)
2336 strcat (dir_name
, ":");
2337 strcat (dir_name
, path
);
2338 /* attach to front since we're going up directory tree */
2339 strcpy (path
, dir_name
);
2341 while (cipb
.dirInfo
.ioDrDirID
!= fsRtDirID
);
2342 /* stop when we see the volume's root directory */
2344 return 1; /* success */
2349 posix_pathname_to_fsspec (ufn
, fs
)
2353 Str255 mac_pathname
;
2355 if (posix_to_mac_pathname (ufn
, mac_pathname
, sizeof (mac_pathname
)) == 0)
2359 c2pstr (mac_pathname
);
2360 return FSMakeFSSpec (0, 0, mac_pathname
, fs
);
2365 fsspec_to_posix_pathname (fs
, ufn
, ufnbuflen
)
2370 char mac_pathname
[MAXPATHLEN
];
2372 if (path_from_vol_dir_name (mac_pathname
, sizeof (mac_pathname
) - 1,
2373 fs
->vRefNum
, fs
->parID
, fs
->name
)
2374 && mac_to_posix_pathname (mac_pathname
, ufn
, ufnbuflen
))
2383 readlink (const char *path
, char *buf
, int bufsiz
)
2385 char mac_sym_link_name
[MAXPATHLEN
+1];
2388 Boolean target_is_folder
, was_aliased
;
2389 Str255 directory_name
, mac_pathname
;
2392 if (posix_to_mac_pathname (path
, mac_sym_link_name
, MAXPATHLEN
+1) == 0)
2395 c2pstr (mac_sym_link_name
);
2396 err
= FSMakeFSSpec (0, 0, mac_sym_link_name
, &fsspec
);
2403 err
= ResolveAliasFile (&fsspec
, true, &target_is_folder
, &was_aliased
);
2404 if (err
!= noErr
|| !was_aliased
)
2410 if (path_from_vol_dir_name (mac_pathname
, 255, fsspec
.vRefNum
, fsspec
.parID
,
2417 if (mac_to_posix_pathname (mac_pathname
, buf
, bufsiz
) == 0)
2423 return strlen (buf
);
2427 /* Convert a path to one with aliases fully expanded. */
2430 find_true_pathname (const char *path
, char *buf
, int bufsiz
)
2432 char *q
, temp
[MAXPATHLEN
+1];
2436 if (bufsiz
<= 0 || path
== 0 || path
[0] == '\0')
2443 q
= strchr (p
+ 1, '/');
2445 q
= strchr (p
, '/');
2446 len
= 0; /* loop may not be entered, e.g., for "/" */
2451 strncat (temp
, p
, q
- p
);
2452 len
= readlink (temp
, buf
, bufsiz
);
2455 if (strlen (temp
) + 1 > bufsiz
)
2465 if (len
+ strlen (p
) + 1 >= bufsiz
)
2469 return len
+ strlen (p
);
2474 umask (mode_t numask
)
2476 static mode_t mask
= 022;
2477 mode_t oldmask
= mask
;
2484 chmod (const char *path
, mode_t mode
)
2486 /* say it always succeed for now */
2492 fchmod (int fd
, mode_t mode
)
2494 /* say it always succeed for now */
2500 fchown (int fd
, uid_t owner
, gid_t group
)
2502 /* say it always succeed for now */
2511 return fcntl (oldd
, F_DUPFD
, 0);
2513 /* current implementation of fcntl in fcntl.mac.c simply returns old
2515 return fcntl (oldd
, F_DUPFD
);
2522 /* This is from the original sysdep.c. Emulate BSD dup2. First close
2523 newd if it already exists. Then, attempt to dup oldd. If not
2524 successful, call dup2 recursively until we are, then close the
2525 unsuccessful ones. */
2528 dup2 (int oldd
, int newd
)
2539 ret
= dup2 (oldd
, newd
);
2545 /* let it fail for now */
2562 ioctl (int d
, int request
, void *argp
)
2572 if (fildes
>=0 && fildes
<= 2)
2605 #endif /* __MRC__ */
2609 #if __MSL__ < 0x6000
2617 #endif /* __MWERKS__ */
2619 #endif /* ! MAC_OSX */
2622 /* Return the path to the directory in which Emacs can create
2623 temporary files. The MacOS "temporary items" directory cannot be
2624 used because it removes the file written by a process when it
2625 exits. In that sense it's more like "/dev/null" than "/tmp" (but
2626 again not exactly). And of course Emacs needs to read back the
2627 files written by its subprocesses. So here we write the files to a
2628 directory "Emacs" in the Preferences Folder. This directory is
2629 created if it does not exist. */
2632 get_temp_dir_name ()
2634 static char *temp_dir_name
= NULL
;
2638 Str255 dir_name
, full_path
;
2640 char unix_dir_name
[MAXPATHLEN
+1];
2643 /* Cache directory name with pointer temp_dir_name.
2644 Look for it only the first time. */
2647 err
= FindFolder (kOnSystemDisk
, kPreferencesFolderType
, kCreateFolder
,
2648 &vol_ref_num
, &dir_id
);
2652 if (!path_from_vol_dir_name (full_path
, 255, vol_ref_num
, dir_id
, "\p"))
2655 if (strlen (full_path
) + 6 <= MAXPATHLEN
)
2656 strcat (full_path
, "Emacs:");
2660 if (!mac_to_posix_pathname (full_path
, unix_dir_name
, MAXPATHLEN
+1))
2663 dir
= opendir (unix_dir_name
); /* check whether temp directory exists */
2666 else if (mkdir (unix_dir_name
, 0700) != 0) /* create it if not */
2669 temp_dir_name
= (char *) malloc (strlen (unix_dir_name
) + 1);
2670 strcpy (temp_dir_name
, unix_dir_name
);
2673 return temp_dir_name
;
2678 /* Allocate and construct an array of pointers to strings from a list
2679 of strings stored in a 'STR#' resource. The returned pointer array
2680 is stored in the style of argv and environ: if the 'STR#' resource
2681 contains numString strings, a pointer array with numString+1
2682 elements is returned in which the last entry contains a null
2683 pointer. The pointer to the pointer array is passed by pointer in
2684 parameter t. The resource ID of the 'STR#' resource is passed in
2685 parameter StringListID.
2689 get_string_list (char ***t
, short string_list_id
)
2695 h
= GetResource ('STR#', string_list_id
);
2700 num_strings
= * (short *) p
;
2702 *t
= (char **) malloc (sizeof (char *) * (num_strings
+ 1));
2703 for (i
= 0; i
< num_strings
; i
++)
2705 short length
= *p
++;
2706 (*t
)[i
] = (char *) malloc (length
+ 1);
2707 strncpy ((*t
)[i
], p
, length
);
2708 (*t
)[i
][length
] = '\0';
2711 (*t
)[num_strings
] = 0;
2716 /* Return no string in case GetResource fails. Bug fixed by
2717 Ikegami Tsutomu. Caused MPW build to crash without sym -on
2718 option (no sym -on implies -opt local). */
2719 *t
= (char **) malloc (sizeof (char *));
2726 get_path_to_system_folder ()
2731 Str255 dir_name
, full_path
;
2733 static char system_folder_unix_name
[MAXPATHLEN
+1];
2736 err
= FindFolder (kOnSystemDisk
, kSystemFolderType
, kDontCreateFolder
,
2737 &vol_ref_num
, &dir_id
);
2741 if (!path_from_vol_dir_name (full_path
, 255, vol_ref_num
, dir_id
, "\p"))
2744 if (!mac_to_posix_pathname (full_path
, system_folder_unix_name
,
2748 return system_folder_unix_name
;
2754 #define ENVIRON_STRING_LIST_ID 128
2756 /* Get environment variable definitions from STR# resource. */
2763 get_string_list (&environ
, ENVIRON_STRING_LIST_ID
);
2769 /* Make HOME directory the one Emacs starts up in if not specified
2771 if (getenv ("HOME") == NULL
)
2773 environ
= (char **) realloc (environ
, sizeof (char *) * (i
+ 2));
2776 environ
[i
] = (char *) malloc (strlen (my_passwd_dir
) + 6);
2779 strcpy (environ
[i
], "HOME=");
2780 strcat (environ
[i
], my_passwd_dir
);
2787 /* Make HOME directory the one Emacs starts up in if not specified
2789 if (getenv ("MAIL") == NULL
)
2791 environ
= (char **) realloc (environ
, sizeof (char *) * (i
+ 2));
2794 char * path_to_system_folder
= get_path_to_system_folder ();
2795 environ
[i
] = (char *) malloc (strlen (path_to_system_folder
) + 22);
2798 strcpy (environ
[i
], "MAIL=");
2799 strcat (environ
[i
], path_to_system_folder
);
2800 strcat (environ
[i
], "Eudora Folder/In");
2808 /* Return the value of the environment variable NAME. */
2811 getenv (const char *name
)
2813 int length
= strlen(name
);
2816 for (e
= environ
; *e
!= 0; e
++)
2817 if (strncmp(*e
, name
, length
) == 0 && (*e
)[length
] == '=')
2818 return &(*e
)[length
+ 1];
2820 if (strcmp (name
, "TMPDIR") == 0)
2821 return get_temp_dir_name ();
2828 /* see Interfaces&Libraries:Interfaces:CIncludes:signal.h */
2829 char *sys_siglist
[] =
2831 "Zero is not a signal!!!",
2833 "Interactive user interrupt", /* 2 */ "?",
2834 "Floating point exception", /* 4 */ "?", "?", "?",
2835 "Illegal instruction", /* 8 */ "?", "?", "?", "?", "?", "?", "?",
2836 "Segment violation", /* 16 */ "?", "?", "?", "?", "?", "?", "?",
2837 "?", "?", "?", "?", "?", "?", "?", "?",
2841 char *sys_siglist
[] =
2843 "Zero is not a signal!!!",
2845 "Floating point exception",
2846 "Illegal instruction",
2847 "Interactive user interrupt",
2848 "Segment violation",
2851 #else /* not __MRC__ and not __MWERKS__ */
2853 #endif /* not __MRC__ and not __MWERKS__ */
2856 #include <utsname.h>
2859 uname (struct utsname
*name
)
2862 system_name
= GetString (-16413); /* IM - Resource Manager Reference */
2865 BlockMove (*system_name
, name
->nodename
, (*system_name
)[0]+1);
2866 p2cstr (name
->nodename
);
2874 /* Event class of HLE sent to subprocess. */
2875 const OSType kEmacsSubprocessSend
= 'ESND';
2877 /* Event class of HLE sent back from subprocess. */
2878 const OSType kEmacsSubprocessReply
= 'ERPY';
2882 mystrchr (char *s
, char c
)
2884 while (*s
&& *s
!= c
)
2912 mystrcpy (char *to
, char *from
)
2924 /* Start a Mac subprocess. Arguments for it is passed in argv (null
2925 terminated). The process should run with the default directory
2926 "workdir", read input from "infn", and write output and error to
2927 "outfn" and "errfn", resp. The Process Manager call
2928 LaunchApplication is used to start the subprocess. We use high
2929 level events as the mechanism to pass arguments to the subprocess
2930 and to make Emacs wait for the subprocess to terminate and pass
2931 back a result code. The bulk of the code here packs the arguments
2932 into one message to be passed together with the high level event.
2933 Emacs also sometimes starts a subprocess using a shell to perform
2934 wildcard filename expansion. Since we don't really have a shell on
2935 the Mac, this case is detected and the starting of the shell is
2936 by-passed. We really need to add code here to do filename
2937 expansion to support such functionality. */
2940 run_mac_command (argv
, workdir
, infn
, outfn
, errfn
)
2941 unsigned char **argv
;
2942 const char *workdir
;
2943 const char *infn
, *outfn
, *errfn
;
2945 #if TARGET_API_MAC_CARBON
2947 #else /* not TARGET_API_MAC_CARBON */
2948 char macappname
[MAXPATHLEN
+1], macworkdir
[MAXPATHLEN
+1];
2949 char macinfn
[MAXPATHLEN
+1], macoutfn
[MAXPATHLEN
+1], macerrfn
[MAXPATHLEN
+1];
2950 int paramlen
, argc
, newargc
, j
, retries
;
2951 char **newargv
, *param
, *p
;
2954 LaunchParamBlockRec lpbr
;
2955 EventRecord send_event
, reply_event
;
2956 RgnHandle cursor_region_handle
;
2958 unsigned long ref_con
, len
;
2960 if (posix_to_mac_pathname (workdir
, macworkdir
, MAXPATHLEN
+1) == 0)
2962 if (posix_to_mac_pathname (infn
, macinfn
, MAXPATHLEN
+1) == 0)
2964 if (posix_to_mac_pathname (outfn
, macoutfn
, MAXPATHLEN
+1) == 0)
2966 if (posix_to_mac_pathname (errfn
, macerrfn
, MAXPATHLEN
+1) == 0)
2969 paramlen
= strlen (macworkdir
) + strlen (macinfn
) + strlen (macoutfn
)
2970 + strlen (macerrfn
) + 4; /* count nulls at end of strings */
2979 /* If a subprocess is invoked with a shell, we receive 3 arguments
2980 of the form: "<path to emacs bins>/sh" "-c" "<path to emacs
2981 bins>/<command> <command args>" */
2982 j
= strlen (argv
[0]);
2983 if (j
>= 3 && strcmp (argv
[0]+j
-3, "/sh") == 0
2984 && argc
== 3 && strcmp (argv
[1], "-c") == 0)
2986 char *command
, *t
, tempmacpathname
[MAXPATHLEN
+1];
2988 /* The arguments for the command in argv[2] are separated by
2989 spaces. Count them and put the count in newargc. */
2990 command
= (char *) alloca (strlen (argv
[2])+2);
2991 strcpy (command
, argv
[2]);
2992 if (command
[strlen (command
) - 1] != ' ')
2993 strcat (command
, " ");
2997 t
= mystrchr (t
, ' ');
3001 t
= mystrchr (t
+1, ' ');
3004 newargv
= (char **) alloca (sizeof (char *) * newargc
);
3007 for (j
= 0; j
< newargc
; j
++)
3009 newargv
[j
] = (char *) alloca (strlen (t
) + 1);
3010 mystrcpy (newargv
[j
], t
);
3013 paramlen
+= strlen (newargv
[j
]) + 1;
3016 if (strncmp (newargv
[0], "~emacs/", 7) == 0)
3018 if (posix_to_mac_pathname (newargv
[0], tempmacpathname
, MAXPATHLEN
+1)
3023 { /* sometimes Emacs call "sh" without a path for the command */
3025 char *t
= (char *) alloca (strlen (newargv
[0]) + 7 + 1);
3026 strcpy (t
, "~emacs/");
3027 strcat (t
, newargv
[0]);
3030 openp (Vexec_path
, build_string (newargv
[0]), Vexec_suffixes
, &path
,
3031 make_number (X_OK
));
3035 if (posix_to_mac_pathname (SDATA (path
), tempmacpathname
,
3039 strcpy (macappname
, tempmacpathname
);
3043 if (posix_to_mac_pathname (argv
[0], macappname
, MAXPATHLEN
+1) == 0)
3046 newargv
= (char **) alloca (sizeof (char *) * argc
);
3048 for (j
= 1; j
< argc
; j
++)
3050 if (strncmp (argv
[j
], "~emacs/", 7) == 0)
3052 char *t
= strchr (argv
[j
], ' ');
3055 char tempcmdname
[MAXPATHLEN
+1], tempmaccmdname
[MAXPATHLEN
+1];
3056 strncpy (tempcmdname
, argv
[j
], t
-argv
[j
]);
3057 tempcmdname
[t
-argv
[j
]] = '\0';
3058 if (posix_to_mac_pathname (tempcmdname
, tempmaccmdname
,
3061 newargv
[j
] = (char *) alloca (strlen (tempmaccmdname
)
3063 strcpy (newargv
[j
], tempmaccmdname
);
3064 strcat (newargv
[j
], t
);
3068 char tempmaccmdname
[MAXPATHLEN
+1];
3069 if (posix_to_mac_pathname (argv
[j
], tempmaccmdname
,
3072 newargv
[j
] = (char *) alloca (strlen (tempmaccmdname
)+1);
3073 strcpy (newargv
[j
], tempmaccmdname
);
3077 newargv
[j
] = argv
[j
];
3078 paramlen
+= strlen (newargv
[j
]) + 1;
3082 /* After expanding all the arguments, we now know the length of the
3083 parameter block to be sent to the subprocess as a message
3084 attached to the HLE. */
3085 param
= (char *) malloc (paramlen
+ 1);
3091 /* first byte of message contains number of arguments for command */
3092 strcpy (p
, macworkdir
);
3093 p
+= strlen (macworkdir
);
3095 /* null terminate strings sent so it's possible to use strcpy over there */
3096 strcpy (p
, macinfn
);
3097 p
+= strlen (macinfn
);
3099 strcpy (p
, macoutfn
);
3100 p
+= strlen (macoutfn
);
3102 strcpy (p
, macerrfn
);
3103 p
+= strlen (macerrfn
);
3105 for (j
= 1; j
< newargc
; j
++)
3107 strcpy (p
, newargv
[j
]);
3108 p
+= strlen (newargv
[j
]);
3112 c2pstr (macappname
);
3114 iErr
= FSMakeFSSpec (0, 0, macappname
, &spec
);
3122 lpbr
.launchBlockID
= extendedBlock
;
3123 lpbr
.launchEPBLength
= extendedBlockLen
;
3124 lpbr
.launchControlFlags
= launchContinue
+ launchNoFileFlags
;
3125 lpbr
.launchAppSpec
= &spec
;
3126 lpbr
.launchAppParameters
= NULL
;
3128 iErr
= LaunchApplication (&lpbr
); /* call the subprocess */
3135 send_event
.what
= kHighLevelEvent
;
3136 send_event
.message
= kEmacsSubprocessSend
;
3137 /* Event ID stored in "where" unused */
3140 /* OS may think current subprocess has terminated if previous one
3141 terminated recently. */
3144 iErr
= PostHighLevelEvent (&send_event
, &lpbr
.launchProcessSN
, 0, param
,
3145 paramlen
+ 1, receiverIDisPSN
);
3147 while (iErr
== sessClosedErr
&& retries
-- > 0);
3155 cursor_region_handle
= NewRgn ();
3157 /* Wait for the subprocess to finish, when it will send us a ERPY
3158 high level event. */
3160 if (WaitNextEvent (highLevelEventMask
, &reply_event
, 180,
3161 cursor_region_handle
)
3162 && reply_event
.message
== kEmacsSubprocessReply
)
3165 /* The return code is sent through the refCon */
3166 iErr
= AcceptHighLevelEvent (&targ
, &ref_con
, NULL
, &len
);
3169 DisposeHandle ((Handle
) cursor_region_handle
);
3174 DisposeHandle ((Handle
) cursor_region_handle
);
3178 #endif /* not TARGET_API_MAC_CARBON */
3183 opendir (const char *dirname
)
3185 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
3186 char mac_pathname
[MAXPATHLEN
+1], vol_name
[MAXPATHLEN
+1];
3190 int len
, vol_name_len
;
3192 if (find_true_pathname (dirname
, true_pathname
, MAXPATHLEN
+1) == -1)
3195 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
3197 fully_resolved_name
[len
] = '\0';
3199 strcpy (fully_resolved_name
, true_pathname
);
3201 dirp
= (DIR *) malloc (sizeof(DIR));
3205 /* Handle special case when dirname is "/": sets up for readir to
3206 get all mount volumes. */
3207 if (strcmp (fully_resolved_name
, "/") == 0)
3209 dirp
->getting_volumes
= 1; /* special all mounted volumes DIR struct */
3210 dirp
->current_index
= 1; /* index for first volume */
3214 /* Handle typical cases: not accessing all mounted volumes. */
3215 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
3218 /* Emacs calls opendir without the trailing '/', Mac needs trailing ':' */
3219 len
= strlen (mac_pathname
);
3220 if (mac_pathname
[len
- 1] != ':' && len
< MAXPATHLEN
)
3221 strcat (mac_pathname
, ":");
3223 /* Extract volume name */
3224 vol_name_len
= strchr (mac_pathname
, ':') - mac_pathname
;
3225 strncpy (vol_name
, mac_pathname
, vol_name_len
);
3226 vol_name
[vol_name_len
] = '\0';
3227 strcat (vol_name
, ":");
3229 c2pstr (mac_pathname
);
3230 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
3231 /* using full pathname so vRefNum and DirID ignored */
3232 cipb
.hFileInfo
.ioVRefNum
= 0;
3233 cipb
.hFileInfo
.ioDirID
= 0;
3234 cipb
.hFileInfo
.ioFDirIndex
= 0;
3235 /* set to 0 to get information about specific dir or file */
3237 errno
= PBGetCatInfo (&cipb
, false);
3244 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x10)) /* bit 4 = 1 for directories */
3245 return 0; /* not a directory */
3247 dirp
->dir_id
= cipb
.dirInfo
.ioDrDirID
; /* used later in readdir */
3248 dirp
->getting_volumes
= 0;
3249 dirp
->current_index
= 1; /* index for first file/directory */
3252 vpb
.ioNamePtr
= vol_name
;
3253 /* using full pathname so vRefNum and DirID ignored */
3255 vpb
.ioVolIndex
= -1;
3256 errno
= PBHGetVInfo ((union HParamBlockRec
*) &vpb
, false);
3263 dirp
->vol_ref_num
= vpb
.ioVRefNum
;
3280 HParamBlockRec hpblock
;
3282 static struct dirent s_dirent
;
3283 static Str255 s_name
;
3287 /* Handle the root directory containing the mounted volumes. Call
3288 PBHGetVInfo specifying an index to obtain the info for a volume.
3289 PBHGetVInfo returns an error when it receives an index beyond the
3290 last volume, at which time we should return a nil dirent struct
3292 if (dp
->getting_volumes
)
3294 hpblock
.volumeParam
.ioNamePtr
= s_name
;
3295 hpblock
.volumeParam
.ioVRefNum
= 0;
3296 hpblock
.volumeParam
.ioVolIndex
= dp
->current_index
;
3298 errno
= PBHGetVInfo (&hpblock
, false);
3306 strcat (s_name
, "/"); /* need "/" for stat to work correctly */
3308 dp
->current_index
++;
3310 s_dirent
.d_ino
= hpblock
.volumeParam
.ioVRefNum
;
3311 s_dirent
.d_name
= s_name
;
3317 cipb
.hFileInfo
.ioVRefNum
= dp
->vol_ref_num
;
3318 cipb
.hFileInfo
.ioNamePtr
= s_name
;
3319 /* location to receive filename returned */
3321 /* return only visible files */
3325 cipb
.hFileInfo
.ioDirID
= dp
->dir_id
;
3326 /* directory ID found by opendir */
3327 cipb
.hFileInfo
.ioFDirIndex
= dp
->current_index
;
3329 errno
= PBGetCatInfo (&cipb
, false);
3336 /* insist on a visible entry */
3337 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* directory? */
3338 done
= !(cipb
.dirInfo
.ioDrUsrWds
.frFlags
& fInvisible
);
3340 done
= !(cipb
.hFileInfo
.ioFlFndrInfo
.fdFlags
& fInvisible
);
3342 dp
->current_index
++;
3355 s_dirent
.d_ino
= cipb
.dirInfo
.ioDrDirID
;
3356 /* value unimportant: non-zero for valid file */
3357 s_dirent
.d_name
= s_name
;
3367 char mac_pathname
[MAXPATHLEN
+1];
3368 Str255 directory_name
;
3372 if (path_from_vol_dir_name (mac_pathname
, 255, 0, 0, "\p") == 0)
3375 if (mac_to_posix_pathname (mac_pathname
, path
, MAXPATHLEN
+1) == 0)
3381 #endif /* ! MAC_OSX */
3385 initialize_applescript ()
3390 /* if open fails, as_scripting_component is set to NULL. Its
3391 subsequent use in OSA calls will fail with badComponentInstance
3393 as_scripting_component
= OpenDefaultComponent (kOSAComponentType
,
3394 kAppleScriptSubtype
);
3396 null_desc
.descriptorType
= typeNull
;
3397 null_desc
.dataHandle
= 0;
3398 osaerror
= OSAMakeContext (as_scripting_component
, &null_desc
,
3399 kOSANullScript
, &as_script_context
);
3401 as_script_context
= kOSANullScript
;
3402 /* use default context if create fails */
3407 terminate_applescript()
3409 OSADispose (as_scripting_component
, as_script_context
);
3410 CloseComponent (as_scripting_component
);
3413 /* Convert a lisp string to the 4 byte character code. */
3416 mac_get_code_from_arg(Lisp_Object arg
, OSType defCode
)
3425 /* check type string */
3427 if (SBYTES (arg
) != 4)
3429 error ("Wrong argument: need string of length 4 for code");
3431 result
= EndianU32_BtoN (*((UInt32
*) SDATA (arg
)));
3436 /* Convert the 4 byte character code into a 4 byte string. */
3439 mac_get_object_from_code(OSType defCode
)
3441 UInt32 code
= EndianU32_NtoB (defCode
);
3443 return make_unibyte_string ((char *)&code
, 4);
3447 DEFUN ("mac-get-file-creator", Fmac_get_file_creator
, Smac_get_file_creator
, 1, 1, 0,
3448 doc
: /* Get the creator code of FILENAME as a four character string. */)
3450 Lisp_Object filename
;
3459 Lisp_Object result
= Qnil
;
3460 CHECK_STRING (filename
);
3462 if (NILP(Ffile_exists_p(filename
)) || !NILP(Ffile_directory_p(filename
))) {
3465 filename
= Fexpand_file_name (filename
, Qnil
);
3469 status
= FSPathMakeRef(SDATA(ENCODE_FILE(filename
)), &fref
, NULL
);
3471 status
= posix_pathname_to_fsspec (SDATA (ENCODE_FILE (filename
)), &fss
);
3474 if (status
== noErr
)
3477 FSCatalogInfo catalogInfo
;
3479 status
= FSGetCatalogInfo(&fref
, kFSCatInfoFinderInfo
,
3480 &catalogInfo
, NULL
, NULL
, NULL
);
3484 status
= FSpGetFInfo (&fss
, &finder_info
);
3486 if (status
== noErr
)
3489 result
= mac_get_object_from_code(((FileInfo
*)&catalogInfo
.finderInfo
)->fileCreator
);
3491 result
= mac_get_object_from_code (finder_info
.fdCreator
);
3496 if (status
!= noErr
) {
3497 error ("Error while getting file information.");
3502 DEFUN ("mac-get-file-type", Fmac_get_file_type
, Smac_get_file_type
, 1, 1, 0,
3503 doc
: /* Get the type code of FILENAME as a four character string. */)
3505 Lisp_Object filename
;
3514 Lisp_Object result
= Qnil
;
3515 CHECK_STRING (filename
);
3517 if (NILP(Ffile_exists_p(filename
)) || !NILP(Ffile_directory_p(filename
))) {
3520 filename
= Fexpand_file_name (filename
, Qnil
);
3524 status
= FSPathMakeRef(SDATA(ENCODE_FILE(filename
)), &fref
, NULL
);
3526 status
= posix_pathname_to_fsspec (SDATA (ENCODE_FILE (filename
)), &fss
);
3529 if (status
== noErr
)
3532 FSCatalogInfo catalogInfo
;
3534 status
= FSGetCatalogInfo(&fref
, kFSCatInfoFinderInfo
,
3535 &catalogInfo
, NULL
, NULL
, NULL
);
3539 status
= FSpGetFInfo (&fss
, &finder_info
);
3541 if (status
== noErr
)
3544 result
= mac_get_object_from_code(((FileInfo
*)&catalogInfo
.finderInfo
)->fileType
);
3546 result
= mac_get_object_from_code (finder_info
.fdType
);
3551 if (status
!= noErr
) {
3552 error ("Error while getting file information.");
3557 DEFUN ("mac-set-file-creator", Fmac_set_file_creator
, Smac_set_file_creator
, 1, 2, 0,
3558 doc
: /* Set creator code of file FILENAME to CODE.
3559 If non-nil, CODE must be a 4-character string. Otherwise, 'EMAx' is
3560 assumed. Return non-nil if successful. */)
3562 Lisp_Object filename
, code
;
3571 CHECK_STRING (filename
);
3573 cCode
= mac_get_code_from_arg(code
, 'EMAx');
3575 if (NILP(Ffile_exists_p(filename
)) || !NILP(Ffile_directory_p(filename
))) {
3578 filename
= Fexpand_file_name (filename
, Qnil
);
3582 status
= FSPathMakeRef(SDATA(ENCODE_FILE(filename
)), &fref
, NULL
);
3584 status
= posix_pathname_to_fsspec (SDATA (ENCODE_FILE (filename
)), &fss
);
3587 if (status
== noErr
)
3590 FSCatalogInfo catalogInfo
;
3592 status
= FSGetCatalogInfo(&fref
, kFSCatInfoFinderInfo
,
3593 &catalogInfo
, NULL
, NULL
, &parentDir
);
3597 status
= FSpGetFInfo (&fss
, &finder_info
);
3599 if (status
== noErr
)
3602 ((FileInfo
*)&catalogInfo
.finderInfo
)->fileCreator
= cCode
;
3603 status
= FSSetCatalogInfo(&fref
, kFSCatInfoFinderInfo
, &catalogInfo
);
3604 /* TODO: on Mac OS 10.2, we need to touch the parent dir, FNNotify? */
3606 finder_info
.fdCreator
= cCode
;
3607 status
= FSpSetFInfo (&fss
, &finder_info
);
3612 if (status
!= noErr
) {
3613 error ("Error while setting creator information.");
3618 DEFUN ("mac-set-file-type", Fmac_set_file_type
, Smac_set_file_type
, 2, 2, 0,
3619 doc
: /* Set file code of file FILENAME to CODE.
3620 CODE must be a 4-character string. Return non-nil if successful. */)
3622 Lisp_Object filename
, code
;
3631 CHECK_STRING (filename
);
3633 cCode
= mac_get_code_from_arg(code
, 0); /* Default to empty code*/
3635 if (NILP(Ffile_exists_p(filename
)) || !NILP(Ffile_directory_p(filename
))) {
3638 filename
= Fexpand_file_name (filename
, Qnil
);
3642 status
= FSPathMakeRef(SDATA(ENCODE_FILE(filename
)), &fref
, NULL
);
3644 status
= posix_pathname_to_fsspec (SDATA (ENCODE_FILE (filename
)), &fss
);
3647 if (status
== noErr
)
3650 FSCatalogInfo catalogInfo
;
3652 status
= FSGetCatalogInfo(&fref
, kFSCatInfoFinderInfo
,
3653 &catalogInfo
, NULL
, NULL
, &parentDir
);
3657 status
= FSpGetFInfo (&fss
, &finder_info
);
3659 if (status
== noErr
)
3662 ((FileInfo
*)&catalogInfo
.finderInfo
)->fileType
= cCode
;
3663 status
= FSSetCatalogInfo(&fref
, kFSCatInfoFinderInfo
, &catalogInfo
);
3664 /* TODO: on Mac OS 10.2, we need to touch the parent dir, FNNotify? */
3666 finder_info
.fdType
= cCode
;
3667 status
= FSpSetFInfo (&fss
, &finder_info
);
3672 if (status
!= noErr
) {
3673 error ("Error while setting creator information.");
3679 /* Compile and execute the AppleScript SCRIPT and return the error
3680 status as function value. A zero is returned if compilation and
3681 execution is successful, in which case RESULT returns a pointer to
3682 a string containing the resulting script value. Otherwise, the Mac
3683 error code is returned and RESULT returns a pointer to an error
3684 string. In both cases the caller should deallocate the storage
3685 used by the string pointed to by RESULT if it is non-NULL. For
3686 documentation on the MacOS scripting architecture, see Inside
3687 Macintosh - Interapplication Communications: Scripting Components. */
3690 do_applescript (char *script
, char **result
)
3692 AEDesc script_desc
, result_desc
, error_desc
;
3699 if (!as_scripting_component
)
3700 initialize_applescript();
3702 error
= AECreateDesc (typeChar
, script
, strlen(script
), &script_desc
);
3706 osaerror
= OSADoScript (as_scripting_component
, &script_desc
, kOSANullScript
,
3707 typeChar
, kOSAModeNull
, &result_desc
);
3709 if (osaerror
== errOSAScriptError
)
3711 /* error executing AppleScript: retrieve error message */
3712 if (!OSAScriptError (as_scripting_component
, kOSAErrorMessage
, typeChar
,
3715 #if TARGET_API_MAC_CARBON
3716 length
= AEGetDescDataSize (&error_desc
);
3717 *result
= (char *) xmalloc (length
+ 1);
3720 AEGetDescData (&error_desc
, *result
, length
);
3721 *(*result
+ length
) = '\0';
3723 #else /* not TARGET_API_MAC_CARBON */
3724 HLock (error_desc
.dataHandle
);
3725 length
= GetHandleSize(error_desc
.dataHandle
);
3726 *result
= (char *) xmalloc (length
+ 1);
3729 memcpy (*result
, *(error_desc
.dataHandle
), length
);
3730 *(*result
+ length
) = '\0';
3732 HUnlock (error_desc
.dataHandle
);
3733 #endif /* not TARGET_API_MAC_CARBON */
3734 AEDisposeDesc (&error_desc
);
3737 else if (osaerror
== noErr
) /* success: retrieve resulting script value */
3739 #if TARGET_API_MAC_CARBON
3740 length
= AEGetDescDataSize (&result_desc
);
3741 *result
= (char *) xmalloc (length
+ 1);
3744 AEGetDescData (&result_desc
, *result
, length
);
3745 *(*result
+ length
) = '\0';
3747 #else /* not TARGET_API_MAC_CARBON */
3748 HLock (result_desc
.dataHandle
);
3749 length
= GetHandleSize(result_desc
.dataHandle
);
3750 *result
= (char *) xmalloc (length
+ 1);
3753 memcpy (*result
, *(result_desc
.dataHandle
), length
);
3754 *(*result
+ length
) = '\0';
3756 HUnlock (result_desc
.dataHandle
);
3757 #endif /* not TARGET_API_MAC_CARBON */
3758 AEDisposeDesc (&result_desc
);
3761 AEDisposeDesc (&script_desc
);
3767 DEFUN ("do-applescript", Fdo_applescript
, Sdo_applescript
, 1, 1, 0,
3768 doc
: /* Compile and execute AppleScript SCRIPT and return the result.
3769 If compilation and execution are successful, the resulting script
3770 value is returned as a string. Otherwise the function aborts and
3771 displays the error message returned by the AppleScript scripting
3776 char *result
, *temp
;
3777 Lisp_Object lisp_result
;
3780 CHECK_STRING (script
);
3783 status
= do_applescript (SDATA (script
), &result
);
3788 error ("AppleScript error %d", status
);
3791 /* Unfortunately only OSADoScript in do_applescript knows how
3792 how large the resulting script value or error message is
3793 going to be and therefore as caller memory must be
3794 deallocated here. It is necessary to free the error
3795 message before calling error to avoid a memory leak. */
3796 temp
= (char *) alloca (strlen (result
) + 1);
3797 strcpy (temp
, result
);
3804 lisp_result
= build_string (result
);
3811 DEFUN ("mac-file-name-to-posix", Fmac_file_name_to_posix
,
3812 Smac_file_name_to_posix
, 1, 1, 0,
3813 doc
: /* Convert Macintosh FILENAME to Posix form. */)
3815 Lisp_Object filename
;
3817 char posix_filename
[MAXPATHLEN
+1];
3819 CHECK_STRING (filename
);
3821 if (mac_to_posix_pathname (SDATA (filename
), posix_filename
, MAXPATHLEN
))
3822 return build_string (posix_filename
);
3828 DEFUN ("posix-file-name-to-mac", Fposix_file_name_to_mac
,
3829 Sposix_file_name_to_mac
, 1, 1, 0,
3830 doc
: /* Convert Posix FILENAME to Mac form. */)
3832 Lisp_Object filename
;
3834 char mac_filename
[MAXPATHLEN
+1];
3836 CHECK_STRING (filename
);
3838 if (posix_to_mac_pathname (SDATA (filename
), mac_filename
, MAXPATHLEN
))
3839 return build_string (mac_filename
);
3845 #if TARGET_API_MAC_CARBON
3846 static Lisp_Object Qxml
, Qmime_charset
;
3847 static Lisp_Object QNFD
, QNFKD
, QNFC
, QNFKC
, QHFS_plus_D
, QHFS_plus_C
;
3849 DEFUN ("mac-get-preference", Fmac_get_preference
, Smac_get_preference
, 1, 4, 0,
3850 doc
: /* Return the application preference value for KEY.
3851 KEY is either a string specifying a preference key, or a list of key
3852 strings. If it is a list, the (i+1)-th element is used as a key for
3853 the CFDictionary value obtained by the i-th element. Return nil if
3854 lookup is failed at some stage.
3856 Optional arg APPLICATION is an application ID string. If omitted or
3857 nil, that stands for the current application.
3859 Optional arg FORMAT specifies the data format of the return value. If
3860 omitted or nil, each Core Foundation object is converted into a
3861 corresponding Lisp object as follows:
3863 Core Foundation Lisp Tag
3864 ------------------------------------------------------------
3865 CFString Multibyte string string
3866 CFNumber Integer or float number
3867 CFBoolean Symbol (t or nil) boolean
3868 CFDate List of three integers date
3869 (cf. `current-time')
3870 CFData Unibyte string data
3871 CFArray Vector array
3872 CFDictionary Alist or hash table dictionary
3873 (depending on HASH-BOUND)
3875 If it is t, a symbol that represents the type of the original Core
3876 Foundation object is prepended. If it is `xml', the value is returned
3877 as an XML representation.
3879 Optional arg HASH-BOUND specifies which kinds of the list objects,
3880 alists or hash tables, are used as the targets of the conversion from
3881 CFDictionary. If HASH-BOUND is a negative integer or nil, always
3882 generate alists. If HASH-BOUND >= 0, generate an alist if the number
3883 of keys in the dictionary is smaller than HASH-BOUND, and a hash table
3885 (key
, application
, format
, hash_bound
)
3886 Lisp_Object key
, application
, format
, hash_bound
;
3888 CFStringRef app_id
, key_str
;
3889 CFPropertyListRef app_plist
= NULL
, plist
;
3890 Lisp_Object result
= Qnil
, tmp
;
3893 key
= Fcons (key
, Qnil
);
3897 for (tmp
= key
; CONSP (tmp
); tmp
= XCDR (tmp
))
3898 CHECK_STRING_CAR (tmp
);
3900 wrong_type_argument (Qlistp
, key
);
3902 if (!NILP (application
))
3903 CHECK_STRING (application
);
3904 CHECK_SYMBOL (format
);
3905 if (!NILP (hash_bound
))
3906 CHECK_NUMBER (hash_bound
);
3910 app_id
= kCFPreferencesCurrentApplication
;
3911 if (!NILP (application
))
3913 app_id
= cfstring_create_with_string (application
);
3917 key_str
= cfstring_create_with_string (XCAR (key
));
3918 if (key_str
== NULL
)
3920 app_plist
= CFPreferencesCopyAppValue (key_str
, app_id
);
3921 CFRelease (key_str
);
3922 if (app_plist
== NULL
)
3926 for (key
= XCDR (key
); CONSP (key
); key
= XCDR (key
))
3928 if (CFGetTypeID (plist
) != CFDictionaryGetTypeID ())
3930 key_str
= cfstring_create_with_string (XCAR (key
));
3931 if (key_str
== NULL
)
3933 plist
= CFDictionaryGetValue (plist
, key_str
);
3934 CFRelease (key_str
);
3940 if (EQ (format
, Qxml
))
3942 CFDataRef data
= CFPropertyListCreateXMLData (NULL
, plist
);
3945 result
= cfdata_to_lisp (data
);
3950 cfproperty_list_to_lisp (plist
, EQ (format
, Qt
),
3951 NILP (hash_bound
) ? -1 : XINT (hash_bound
));
3955 CFRelease (app_plist
);
3964 static CFStringEncoding
3965 get_cfstring_encoding_from_lisp (obj
)
3968 CFStringRef iana_name
;
3969 CFStringEncoding encoding
= kCFStringEncodingInvalidId
;
3972 return kCFStringEncodingUnicode
;
3977 if (SYMBOLP (obj
) && !NILP (Fcoding_system_p (obj
)))
3979 Lisp_Object coding_spec
, plist
;
3981 coding_spec
= Fget (obj
, Qcoding_system
);
3982 plist
= XVECTOR (coding_spec
)->contents
[3];
3983 obj
= Fplist_get (XVECTOR (coding_spec
)->contents
[3], Qmime_charset
);
3987 obj
= SYMBOL_NAME (obj
);
3991 iana_name
= cfstring_create_with_string (obj
);
3994 encoding
= CFStringConvertIANACharSetNameToEncoding (iana_name
);
3995 CFRelease (iana_name
);
4002 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
4004 cfstring_create_normalized (str
, symbol
)
4009 TextEncodingVariant variant
;
4010 float initial_mag
= 0.0;
4011 CFStringRef result
= NULL
;
4013 if (EQ (symbol
, QNFD
))
4014 form
= kCFStringNormalizationFormD
;
4015 else if (EQ (symbol
, QNFKD
))
4016 form
= kCFStringNormalizationFormKD
;
4017 else if (EQ (symbol
, QNFC
))
4018 form
= kCFStringNormalizationFormC
;
4019 else if (EQ (symbol
, QNFKC
))
4020 form
= kCFStringNormalizationFormKC
;
4021 else if (EQ (symbol
, QHFS_plus_D
))
4023 variant
= kUnicodeHFSPlusDecompVariant
;
4026 else if (EQ (symbol
, QHFS_plus_C
))
4028 variant
= kUnicodeHFSPlusCompVariant
;
4034 CFMutableStringRef mut_str
= CFStringCreateMutableCopy (NULL
, 0, str
);
4038 CFStringNormalize (mut_str
, form
);
4042 else if (initial_mag
> 0.0)
4044 UnicodeToTextInfo uni
= NULL
;
4047 UniChar
*in_text
, *buffer
= NULL
, *out_buf
= NULL
;
4049 ByteCount out_read
, out_size
, out_len
;
4051 map
.unicodeEncoding
= CreateTextEncoding (kTextEncodingUnicodeDefault
,
4053 kTextEncodingDefaultFormat
);
4054 map
.otherEncoding
= CreateTextEncoding (kTextEncodingUnicodeDefault
,
4056 kTextEncodingDefaultFormat
);
4057 map
.mappingVersion
= kUnicodeUseLatestMapping
;
4059 length
= CFStringGetLength (str
);
4060 out_size
= (int)((float)length
* initial_mag
) * sizeof (UniChar
);
4064 in_text
= (UniChar
*)CFStringGetCharactersPtr (str
);
4065 if (in_text
== NULL
)
4067 buffer
= xmalloc (sizeof (UniChar
) * length
);
4070 CFStringGetCharacters (str
, CFRangeMake (0, length
), buffer
);
4076 err
= CreateUnicodeToTextInfo(&map
, &uni
);
4077 while (err
== noErr
)
4079 out_buf
= xmalloc (out_size
);
4080 if (out_buf
== NULL
)
4083 err
= ConvertFromUnicodeToText (uni
, length
* sizeof (UniChar
),
4085 kUnicodeDefaultDirectionMask
,
4086 0, NULL
, NULL
, NULL
,
4087 out_size
, &out_read
, &out_len
,
4089 if (err
== noErr
&& out_read
< length
* sizeof (UniChar
))
4098 result
= CFStringCreateWithCharacters (NULL
, out_buf
,
4099 out_len
/ sizeof (UniChar
));
4101 DisposeUnicodeToTextInfo (&uni
);
4117 DEFUN ("mac-code-convert-string", Fmac_code_convert_string
, Smac_code_convert_string
, 3, 4, 0,
4118 doc
: /* Convert STRING from SOURCE encoding to TARGET encoding.
4119 The conversion is performed using the converter provided by the system.
4120 Each encoding is specified by either a coding system symbol, a mime
4121 charset string, or an integer as a CFStringEncoding value. Nil for
4122 encoding means UTF-16 in native byte order, no byte order mark.
4123 On Mac OS X 10.2 and later, you can do Unicode Normalization by
4124 specifying the optional argument NORMALIZATION-FORM with a symbol NFD,
4125 NFKD, NFC, NFKC, HFS+D, or HFS+C.
4126 On successful conversion, return the result string, else return nil. */)
4127 (string
, source
, target
, normalization_form
)
4128 Lisp_Object string
, source
, target
, normalization_form
;
4130 Lisp_Object result
= Qnil
;
4131 CFStringEncoding src_encoding
, tgt_encoding
;
4132 CFStringRef str
= NULL
;
4134 CHECK_STRING (string
);
4135 if (!INTEGERP (source
) && !STRINGP (source
))
4136 CHECK_SYMBOL (source
);
4137 if (!INTEGERP (target
) && !STRINGP (target
))
4138 CHECK_SYMBOL (target
);
4139 CHECK_SYMBOL (normalization_form
);
4143 src_encoding
= get_cfstring_encoding_from_lisp (source
);
4144 tgt_encoding
= get_cfstring_encoding_from_lisp (target
);
4146 /* We really want string_to_unibyte, but since it doesn't exist yet, we
4147 use string_as_unibyte which works as well, except for the fact that
4148 it's too permissive (it doesn't check that the multibyte string only
4149 contain single-byte chars). */
4150 string
= Fstring_as_unibyte (string
);
4151 if (src_encoding
!= kCFStringEncodingInvalidId
4152 && tgt_encoding
!= kCFStringEncodingInvalidId
)
4153 str
= CFStringCreateWithBytes (NULL
, SDATA (string
), SBYTES (string
),
4154 src_encoding
, !NILP (source
));
4155 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
4158 CFStringRef saved_str
= str
;
4160 str
= cfstring_create_normalized (saved_str
, normalization_form
);
4161 CFRelease (saved_str
);
4166 CFIndex str_len
, buf_len
;
4168 str_len
= CFStringGetLength (str
);
4169 if (CFStringGetBytes (str
, CFRangeMake (0, str_len
), tgt_encoding
, 0,
4170 !NILP (target
), NULL
, 0, &buf_len
) == str_len
)
4172 result
= make_uninit_string (buf_len
);
4173 CFStringGetBytes (str
, CFRangeMake (0, str_len
), tgt_encoding
, 0,
4174 !NILP (target
), SDATA (result
), buf_len
, NULL
);
4183 #endif /* TARGET_API_MAC_CARBON */
4186 DEFUN ("mac-clear-font-name-table", Fmac_clear_font_name_table
, Smac_clear_font_name_table
, 0, 0, 0,
4187 doc
: /* Clear the font name table. */)
4191 mac_clear_font_name_table ();
4197 mac_get_system_locale ()
4205 lang
= GetScriptVariable (smSystemScript
, smScriptLang
);
4206 region
= GetScriptManagerVariable (smRegionCode
);
4207 err
= LocaleRefFromLangOrRegionCode (lang
, region
, &locale
);
4209 err
= LocaleRefGetPartString (locale
, kLocaleAllPartsMask
,
4212 return build_string (str
);
4221 extern int inhibit_window_system
;
4222 extern int noninteractive
;
4224 /* Unlike in X11, window events in Carbon do not come from sockets.
4225 So we cannot simply use `select' to monitor two kinds of inputs:
4226 window events and process outputs. We emulate such functionality
4227 by regarding fd 0 as the window event channel and simultaneously
4228 monitoring both kinds of input channels. It is implemented by
4229 dividing into some cases:
4230 1. The window event channel is not involved.
4232 2. Sockets are not involved.
4233 -> Use ReceiveNextEvent.
4234 3. [If SELECT_USE_CFSOCKET is defined]
4235 Only the window event channel and socket read channels are
4236 involved, and timeout is not too short (greater than
4237 SELECT_TIMEOUT_THRESHHOLD_RUNLOOP seconds).
4238 -> Create CFSocket for each socket and add it into the current
4239 event RunLoop so that a `ready-to-read' event can be posted
4240 to the event queue that is also used for window events. Then
4241 ReceiveNextEvent can wait for both kinds of inputs.
4243 -> Periodically poll the window input channel while repeatedly
4244 executing `select' with a short timeout
4245 (SELECT_POLLING_PERIOD_USEC microseconds). */
4247 #define SELECT_POLLING_PERIOD_USEC 20000
4248 #ifdef SELECT_USE_CFSOCKET
4249 #define SELECT_TIMEOUT_THRESHOLD_RUNLOOP 0.2
4250 #define EVENT_CLASS_SOCK 'Sock'
4253 socket_callback (s
, type
, address
, data
, info
)
4255 CFSocketCallBackType type
;
4262 CreateEvent (NULL
, EVENT_CLASS_SOCK
, 0, 0, kEventAttributeNone
, &event
);
4263 PostEventToQueue (GetCurrentEventQueue (), event
, kEventPriorityStandard
);
4264 ReleaseEvent (event
);
4266 #endif /* SELECT_USE_CFSOCKET */
4269 select_and_poll_event (n
, rfds
, wfds
, efds
, timeout
)
4274 struct timeval
*timeout
;
4279 r
= select (n
, rfds
, wfds
, efds
, timeout
);
4283 err
= ReceiveNextEvent (0, NULL
, kEventDurationNoWait
,
4284 kEventLeaveInQueue
, NULL
);
4295 #if MAC_OS_X_VERSION_MAX_ALLOWED < 1020
4296 #undef SELECT_INVALIDATE_CFSOCKET
4300 sys_select (n
, rfds
, wfds
, efds
, timeout
)
4305 struct timeval
*timeout
;
4309 EMACS_TIME select_timeout
;
4311 if (inhibit_window_system
|| noninteractive
4312 || rfds
== NULL
|| !FD_ISSET (0, rfds
))
4313 return select (n
, rfds
, wfds
, efds
, timeout
);
4317 if (wfds
== NULL
&& efds
== NULL
)
4320 SELECT_TYPE orfds
= *rfds
;
4322 EventTimeout timeout_sec
=
4324 ? (EMACS_SECS (*timeout
) * kEventDurationSecond
4325 + EMACS_USECS (*timeout
) * kEventDurationMicrosecond
)
4326 : kEventDurationForever
);
4328 for (i
= 1; i
< n
; i
++)
4329 if (FD_ISSET (i
, rfds
))
4335 err
= ReceiveNextEvent (0, NULL
, timeout_sec
,
4336 kEventLeaveInQueue
, NULL
);
4347 /* Avoid initial overhead of RunLoop setup for the case that
4348 some input is already available. */
4349 EMACS_SET_SECS_USECS (select_timeout
, 0, 0);
4350 r
= select_and_poll_event (n
, rfds
, wfds
, efds
, &select_timeout
);
4351 if (r
!= 0 || timeout_sec
== 0.0)
4356 #ifdef SELECT_USE_CFSOCKET
4357 if (timeout_sec
> 0 && timeout_sec
<= SELECT_TIMEOUT_THRESHOLD_RUNLOOP
)
4358 goto poll_periodically
;
4361 CFRunLoopRef runloop
=
4362 (CFRunLoopRef
) GetCFRunLoopFromEventLoop (GetCurrentEventLoop ());
4363 EventTypeSpec specs
[] = {{EVENT_CLASS_SOCK
, 0}};
4364 #ifdef SELECT_INVALIDATE_CFSOCKET
4365 CFSocketRef
*shead
, *s
;
4367 CFRunLoopSourceRef
*shead
, *s
;
4372 #ifdef SELECT_INVALIDATE_CFSOCKET
4373 shead
= xmalloc (sizeof (CFSocketRef
) * nsocks
);
4375 shead
= xmalloc (sizeof (CFRunLoopSourceRef
) * nsocks
);
4378 for (i
= 1; i
< n
; i
++)
4379 if (FD_ISSET (i
, rfds
))
4381 CFSocketRef socket
=
4382 CFSocketCreateWithNative (NULL
, i
, kCFSocketReadCallBack
,
4383 socket_callback
, NULL
);
4384 CFRunLoopSourceRef source
=
4385 CFSocketCreateRunLoopSource (NULL
, socket
, 0);
4387 #ifdef SELECT_INVALIDATE_CFSOCKET
4388 CFSocketSetSocketFlags (socket
, 0);
4390 CFRunLoopAddSource (runloop
, source
, kCFRunLoopDefaultMode
);
4391 #ifdef SELECT_INVALIDATE_CFSOCKET
4401 err
= ReceiveNextEvent (0, NULL
, timeout_sec
, kEventLeaveInQueue
, NULL
);
4406 #ifdef SELECT_INVALIDATE_CFSOCKET
4407 CFSocketInvalidate (*s
);
4409 CFRunLoopRemoveSource (runloop
, *s
, kCFRunLoopDefaultMode
);
4424 FlushEventsMatchingListFromQueue (GetCurrentEventQueue (),
4425 GetEventTypeCount (specs
),
4427 EMACS_SET_SECS_USECS (select_timeout
, 0, 0);
4428 r
= select_and_poll_event (n
, rfds
, wfds
, efds
, &select_timeout
);
4435 #endif /* SELECT_USE_CFSOCKET */
4440 EMACS_TIME end_time
, now
, remaining_time
;
4441 SELECT_TYPE orfds
= *rfds
, owfds
, oefds
;
4449 remaining_time
= *timeout
;
4450 EMACS_GET_TIME (now
);
4451 EMACS_ADD_TIME (end_time
, now
, remaining_time
);
4456 EMACS_SET_SECS_USECS (select_timeout
, 0, SELECT_POLLING_PERIOD_USEC
);
4457 if (timeout
&& EMACS_TIME_LT (remaining_time
, select_timeout
))
4458 select_timeout
= remaining_time
;
4459 r
= select_and_poll_event (n
, rfds
, wfds
, efds
, &select_timeout
);
4471 EMACS_GET_TIME (now
);
4472 EMACS_SUB_TIME (remaining_time
, end_time
, now
);
4475 while (!timeout
|| EMACS_TIME_LT (now
, end_time
));
4486 /* Set up environment variables so that Emacs can correctly find its
4487 support files when packaged as an application bundle. Directories
4488 placed in /usr/local/share/emacs/<emacs-version>/, /usr/local/bin,
4489 and /usr/local/libexec/emacs/<emacs-version>/<system-configuration>
4490 by `make install' by default can instead be placed in
4491 .../Emacs.app/Contents/Resources/ and
4492 .../Emacs.app/Contents/MacOS/. Each of these environment variables
4493 is changed only if it is not already set. Presumably if the user
4494 sets an environment variable, he will want to use files in his path
4495 instead of ones in the application bundle. */
4497 init_mac_osx_environment ()
4501 CFStringRef cf_app_bundle_pathname
;
4502 int app_bundle_pathname_len
;
4503 char *app_bundle_pathname
;
4507 /* Initialize locale related variables. */
4508 mac_system_script_code
=
4509 (ScriptCode
) GetScriptManagerVariable (smSysScript
);
4510 Vmac_system_locale
= mac_get_system_locale ();
4512 /* Fetch the pathname of the application bundle as a C string into
4513 app_bundle_pathname. */
4515 bundle
= CFBundleGetMainBundle ();
4516 if (!bundle
|| CFBundleGetIdentifier (bundle
) == NULL
)
4518 /* We could not find the bundle identifier. For now, prevent
4519 the fatal error by bringing it up in the terminal. */
4520 inhibit_window_system
= 1;
4524 bundleURL
= CFBundleCopyBundleURL (bundle
);
4528 cf_app_bundle_pathname
= CFURLCopyFileSystemPath (bundleURL
,
4529 kCFURLPOSIXPathStyle
);
4530 app_bundle_pathname_len
= CFStringGetLength (cf_app_bundle_pathname
);
4531 app_bundle_pathname
= (char *) alloca (app_bundle_pathname_len
+ 1);
4533 if (!CFStringGetCString (cf_app_bundle_pathname
,
4534 app_bundle_pathname
,
4535 app_bundle_pathname_len
+ 1,
4536 kCFStringEncodingISOLatin1
))
4538 CFRelease (cf_app_bundle_pathname
);
4542 CFRelease (cf_app_bundle_pathname
);
4544 /* P should have sufficient room for the pathname of the bundle plus
4545 the subpath in it leading to the respective directories. Q
4546 should have three times that much room because EMACSLOADPATH can
4547 have the value "<path to lisp dir>:<path to leim dir>:<path to
4549 p
= (char *) alloca (app_bundle_pathname_len
+ 50);
4550 q
= (char *) alloca (3 * app_bundle_pathname_len
+ 150);
4551 if (!getenv ("EMACSLOADPATH"))
4555 strcpy (p
, app_bundle_pathname
);
4556 strcat (p
, "/Contents/Resources/lisp");
4557 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
4560 strcpy (p
, app_bundle_pathname
);
4561 strcat (p
, "/Contents/Resources/leim");
4562 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
4569 strcpy (p
, app_bundle_pathname
);
4570 strcat (p
, "/Contents/Resources/site-lisp");
4571 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
4579 setenv ("EMACSLOADPATH", q
, 1);
4582 if (!getenv ("EMACSPATH"))
4586 strcpy (p
, app_bundle_pathname
);
4587 strcat (p
, "/Contents/MacOS/libexec");
4588 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
4591 strcpy (p
, app_bundle_pathname
);
4592 strcat (p
, "/Contents/MacOS/bin");
4593 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
4601 setenv ("EMACSPATH", q
, 1);
4604 if (!getenv ("EMACSDATA"))
4606 strcpy (p
, app_bundle_pathname
);
4607 strcat (p
, "/Contents/Resources/etc");
4608 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
4609 setenv ("EMACSDATA", p
, 1);
4612 if (!getenv ("EMACSDOC"))
4614 strcpy (p
, app_bundle_pathname
);
4615 strcat (p
, "/Contents/Resources/etc");
4616 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
4617 setenv ("EMACSDOC", p
, 1);
4620 if (!getenv ("INFOPATH"))
4622 strcpy (p
, app_bundle_pathname
);
4623 strcat (p
, "/Contents/Resources/info");
4624 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
4625 setenv ("INFOPATH", p
, 1);
4628 #endif /* MAC_OSX */
4634 #if TARGET_API_MAC_CARBON
4635 Qstring
= intern ("string"); staticpro (&Qstring
);
4636 Qnumber
= intern ("number"); staticpro (&Qnumber
);
4637 Qboolean
= intern ("boolean"); staticpro (&Qboolean
);
4638 Qdate
= intern ("date"); staticpro (&Qdate
);
4639 Qdata
= intern ("data"); staticpro (&Qdata
);
4640 Qarray
= intern ("array"); staticpro (&Qarray
);
4641 Qdictionary
= intern ("dictionary"); staticpro (&Qdictionary
);
4643 Qxml
= intern ("xml");
4646 Qmime_charset
= intern ("mime-charset");
4647 staticpro (&Qmime_charset
);
4649 QNFD
= intern ("NFD"); staticpro (&QNFD
);
4650 QNFKD
= intern ("NFKD"); staticpro (&QNFKD
);
4651 QNFC
= intern ("NFC"); staticpro (&QNFC
);
4652 QNFKC
= intern ("NFKC"); staticpro (&QNFKC
);
4653 QHFS_plus_D
= intern ("HFS+D"); staticpro (&QHFS_plus_D
);
4654 QHFS_plus_C
= intern ("HFS+C"); staticpro (&QHFS_plus_C
);
4657 #if TARGET_API_MAC_CARBON
4658 defsubr (&Smac_get_preference
);
4659 defsubr (&Smac_code_convert_string
);
4661 defsubr (&Smac_clear_font_name_table
);
4663 defsubr (&Smac_set_file_creator
);
4664 defsubr (&Smac_set_file_type
);
4665 defsubr (&Smac_get_file_creator
);
4666 defsubr (&Smac_get_file_type
);
4667 defsubr (&Sdo_applescript
);
4668 defsubr (&Smac_file_name_to_posix
);
4669 defsubr (&Sposix_file_name_to_mac
);
4671 DEFVAR_INT ("mac-system-script-code", &mac_system_script_code
,
4672 doc
: /* The system script code. */);
4673 mac_system_script_code
= (ScriptCode
) GetScriptManagerVariable (smSysScript
);
4675 DEFVAR_LISP ("mac-system-locale", &Vmac_system_locale
,
4676 doc
: /* The system locale identifier string.
4677 This is not a POSIX locale ID, but an ICU locale ID. So encoding
4678 information is not included. */);
4679 Vmac_system_locale
= mac_get_system_locale ();
4682 /* arch-tag: 29d30c1f-0c6b-4f88-8a6d-0558d7f9dbff
4683 (do not change this comment) */