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
;
269 struct cfdict_context
272 int with_tag
, hash_bound
;
275 /* C string to CFString. */
278 cfstring_create_with_utf8_cstring (c_str
)
283 str
= CFStringCreateWithCString (NULL
, c_str
, kCFStringEncodingUTF8
);
285 /* Failed to interpret as UTF 8. Fall back on Mac Roman. */
286 str
= CFStringCreateWithCString (NULL
, c_str
, kCFStringEncodingMacRoman
);
292 /* Lisp string to CFString. */
295 cfstring_create_with_string (s
)
298 CFStringRef string
= NULL
;
300 if (STRING_MULTIBYTE (s
))
302 char *p
, *end
= SDATA (s
) + SBYTES (s
);
304 for (p
= SDATA (s
); p
< end
; p
++)
307 s
= ENCODE_UTF_8 (s
);
310 string
= CFStringCreateWithBytes (NULL
, SDATA (s
), SBYTES (s
),
311 kCFStringEncodingUTF8
, false);
315 /* Failed to interpret as UTF 8. Fall back on Mac Roman. */
316 string
= CFStringCreateWithBytes (NULL
, SDATA (s
), SBYTES (s
),
317 kCFStringEncodingMacRoman
, false);
323 /* From CFData to a lisp string. Always returns a unibyte string. */
326 cfdata_to_lisp (data
)
329 CFIndex len
= CFDataGetLength (data
);
330 Lisp_Object result
= make_uninit_string (len
);
332 CFDataGetBytes (data
, CFRangeMake (0, len
), SDATA (result
));
338 /* From CFString to a lisp string. Returns a unibyte string
339 containing a UTF-8 byte sequence. */
342 cfstring_to_lisp_nodecode (string
)
345 Lisp_Object result
= Qnil
;
346 const char *s
= CFStringGetCStringPtr (string
, kCFStringEncodingUTF8
);
349 result
= make_unibyte_string (s
, strlen (s
));
353 CFStringCreateExternalRepresentation (NULL
, string
,
354 kCFStringEncodingUTF8
, '?');
358 result
= cfdata_to_lisp (data
);
367 /* From CFString to a lisp string. Never returns a unibyte string
368 (even if it only contains ASCII characters).
369 This may cause GC during code conversion. */
372 cfstring_to_lisp (string
)
375 Lisp_Object result
= cfstring_to_lisp_nodecode (string
);
379 result
= code_convert_string_norecord (result
, Qutf_8
, 0);
380 /* This may be superfluous. Just to make sure that the result
381 is a multibyte string. */
382 result
= string_to_multibyte (result
);
389 /* CFNumber to a lisp integer or a lisp float. */
392 cfnumber_to_lisp (number
)
395 Lisp_Object result
= Qnil
;
396 #if BITS_PER_EMACS_INT > 32
398 CFNumberType emacs_int_type
= kCFNumberSInt64Type
;
401 CFNumberType emacs_int_type
= kCFNumberSInt32Type
;
405 if (CFNumberGetValue (number
, emacs_int_type
, &int_val
)
406 && !FIXNUM_OVERFLOW_P (int_val
))
407 result
= make_number (int_val
);
409 if (CFNumberGetValue (number
, kCFNumberDoubleType
, &float_val
))
410 result
= make_float (float_val
);
415 /* CFDate to a list of three integers as in a return value of
419 cfdate_to_lisp (date
)
422 static const CFGregorianDate epoch_gdate
= {1970, 1, 1, 0, 0, 0.0};
423 static CFAbsoluteTime epoch
= 0.0, sec
;
427 epoch
= CFGregorianDateGetAbsoluteTime (epoch_gdate
, NULL
);
429 sec
= CFDateGetAbsoluteTime (date
) - epoch
;
430 high
= sec
/ 65536.0;
431 low
= sec
- high
* 65536.0;
433 return list3 (make_number (high
), make_number (low
), make_number (0));
437 /* CFBoolean to a lisp symbol, `t' or `nil'. */
440 cfboolean_to_lisp (boolean
)
441 CFBooleanRef boolean
;
443 return CFBooleanGetValue (boolean
) ? Qt
: Qnil
;
447 /* Any Core Foundation object to a (lengthy) lisp string. */
450 cfobject_desc_to_lisp (object
)
453 Lisp_Object result
= Qnil
;
454 CFStringRef desc
= CFCopyDescription (object
);
458 result
= cfstring_to_lisp (desc
);
466 /* Callback functions for cfproperty_list_to_lisp. */
469 cfdictionary_add_to_list (key
, value
, context
)
474 struct cfdict_context
*cxt
= (struct cfdict_context
*)context
;
477 Fcons (Fcons (cfstring_to_lisp (key
),
478 cfproperty_list_to_lisp (value
, cxt
->with_tag
,
484 cfdictionary_puthash (key
, value
, context
)
489 Lisp_Object lisp_key
= cfstring_to_lisp (key
);
490 struct cfdict_context
*cxt
= (struct cfdict_context
*)context
;
491 struct Lisp_Hash_Table
*h
= XHASH_TABLE (*(cxt
->result
));
494 hash_lookup (h
, lisp_key
, &hash_code
);
495 hash_put (h
, lisp_key
,
496 cfproperty_list_to_lisp (value
, cxt
->with_tag
, cxt
->hash_bound
),
501 /* Convert CFPropertyList PLIST to a lisp object. If WITH_TAG is
502 non-zero, a symbol that represents the type of the original Core
503 Foundation object is prepended. HASH_BOUND specifies which kinds
504 of the lisp objects, alists or hash tables, are used as the targets
505 of the conversion from CFDictionary. If HASH_BOUND is negative,
506 always generate alists. If HASH_BOUND >= 0, generate an alist if
507 the number of keys in the dictionary is smaller than HASH_BOUND,
508 and a hash table otherwise. */
511 cfproperty_list_to_lisp (plist
, with_tag
, hash_bound
)
512 CFPropertyListRef plist
;
513 int with_tag
, hash_bound
;
515 CFTypeID type_id
= CFGetTypeID (plist
);
516 Lisp_Object tag
= Qnil
, result
= Qnil
;
517 struct gcpro gcpro1
, gcpro2
;
519 GCPRO2 (tag
, result
);
521 if (type_id
== CFStringGetTypeID ())
524 result
= cfstring_to_lisp (plist
);
526 else if (type_id
== CFNumberGetTypeID ())
529 result
= cfnumber_to_lisp (plist
);
531 else if (type_id
== CFBooleanGetTypeID ())
534 result
= cfboolean_to_lisp (plist
);
536 else if (type_id
== CFDateGetTypeID ())
539 result
= cfdate_to_lisp (plist
);
541 else if (type_id
== CFDataGetTypeID ())
544 result
= cfdata_to_lisp (plist
);
546 else if (type_id
== CFArrayGetTypeID ())
548 CFIndex index
, count
= CFArrayGetCount (plist
);
551 result
= Fmake_vector (make_number (count
), Qnil
);
552 for (index
= 0; index
< count
; index
++)
553 XVECTOR (result
)->contents
[index
] =
554 cfproperty_list_to_lisp (CFArrayGetValueAtIndex (plist
, index
),
555 with_tag
, hash_bound
);
557 else if (type_id
== CFDictionaryGetTypeID ())
559 struct cfdict_context context
;
560 CFIndex count
= CFDictionaryGetCount (plist
);
563 context
.result
= &result
;
564 context
.with_tag
= with_tag
;
565 context
.hash_bound
= hash_bound
;
566 if (hash_bound
< 0 || count
< hash_bound
)
569 CFDictionaryApplyFunction (plist
, cfdictionary_add_to_list
,
574 result
= make_hash_table (Qequal
,
576 make_float (DEFAULT_REHASH_SIZE
),
577 make_float (DEFAULT_REHASH_THRESHOLD
),
579 CFDictionaryApplyFunction (plist
, cfdictionary_puthash
,
589 result
= Fcons (tag
, result
);
596 /***********************************************************************
597 Emulation of the X Resource Manager
598 ***********************************************************************/
600 /* Parser functions for resource lines. Each function takes an
601 address of a variable whose value points to the head of a string.
602 The value will be advanced so that it points to the next character
603 of the parsed part when the function returns.
605 A resource name such as "Emacs*font" is parsed into a non-empty
606 list called `quarks'. Each element is either a Lisp string that
607 represents a concrete component, a Lisp symbol LOOSE_BINDING
608 (actually Qlambda) that represents any number (>=0) of intervening
609 components, or a Lisp symbol SINGLE_COMPONENT (actually Qquote)
610 that represents as any single component. */
614 #define LOOSE_BINDING Qlambda /* '*' ("L"oose) */
615 #define SINGLE_COMPONENT Qquote /* '?' ("Q"uestion) */
621 /* WhiteSpace = {<space> | <horizontal tab>} */
622 while (*P
== ' ' || *P
== '\t')
630 /* Comment = "!" {<any character except null or newline>} */
643 /* Don't interpret filename. Just skip until the newline. */
645 parse_include_file (p
)
648 /* IncludeFile = "#" WhiteSpace "include" WhiteSpace FileName WhiteSpace */
665 /* Binding = "." | "*" */
666 if (*P
== '.' || *P
== '*')
670 while (*P
== '.' || *P
== '*')
683 /* Component = "?" | ComponentName
684 ComponentName = NameChar {NameChar}
685 NameChar = "a"-"z" | "A"-"Z" | "0"-"9" | "_" | "-" */
689 return SINGLE_COMPONENT
;
691 else if (isalnum (*P
) || *P
== '_' || *P
== '-')
695 while (isalnum (*P
) || *P
== '_' || *P
== '-')
698 return make_unibyte_string (start
, P
- start
);
705 parse_resource_name (p
)
708 Lisp_Object result
= Qnil
, component
;
711 /* ResourceName = [Binding] {Component Binding} ComponentName */
712 if (parse_binding (p
) == '*')
713 result
= Fcons (LOOSE_BINDING
, result
);
715 component
= parse_component (p
);
716 if (NILP (component
))
719 result
= Fcons (component
, result
);
720 while ((binding
= parse_binding (p
)) != '\0')
723 result
= Fcons (LOOSE_BINDING
, result
);
724 component
= parse_component (p
);
725 if (NILP (component
))
728 result
= Fcons (component
, result
);
731 /* The final component should not be '?'. */
732 if (EQ (component
, SINGLE_COMPONENT
))
735 return Fnreverse (result
);
743 Lisp_Object seq
= Qnil
, result
;
744 int buf_len
, total_len
= 0, len
, continue_p
;
746 q
= strchr (P
, '\n');
747 buf_len
= q
? q
- P
: strlen (P
);
748 buf
= xmalloc (buf_len
);
777 else if ('0' <= P
[0] && P
[0] <= '7'
778 && '0' <= P
[1] && P
[1] <= '7'
779 && '0' <= P
[2] && P
[2] <= '7')
781 *q
++ = (P
[0] - '0' << 6) + (P
[1] - '0' << 3) + (P
[2] - '0');
791 seq
= Fcons (make_unibyte_string (buf
, len
), seq
);
796 q
= strchr (P
, '\n');
797 len
= q
? q
- P
: strlen (P
);
802 buf
= xmalloc (buf_len
);
810 if (SBYTES (XCAR (seq
)) == total_len
)
811 return make_string (SDATA (XCAR (seq
)), total_len
);
814 buf
= xmalloc (total_len
);
816 for (; CONSP (seq
); seq
= XCDR (seq
))
818 len
= SBYTES (XCAR (seq
));
820 memcpy (q
, SDATA (XCAR (seq
)), len
);
822 result
= make_string (buf
, total_len
);
829 parse_resource_line (p
)
832 Lisp_Object quarks
, value
;
834 /* ResourceLine = Comment | IncludeFile | ResourceSpec | <empty line> */
835 if (parse_comment (p
) || parse_include_file (p
))
838 /* ResourceSpec = WhiteSpace ResourceName WhiteSpace ":" WhiteSpace Value */
839 skip_white_space (p
);
840 quarks
= parse_resource_name (p
);
843 skip_white_space (p
);
847 skip_white_space (p
);
848 value
= parse_value (p
);
849 return Fcons (quarks
, value
);
852 /* Skip the remaining data as a dummy value. */
859 /* Equivalents of X Resource Manager functions.
861 An X Resource Database acts as a collection of resource names and
862 associated values. It is implemented as a trie on quarks. Namely,
863 each edge is labeled by either a string, LOOSE_BINDING, or
864 SINGLE_COMPONENT. Each node has a node id, which is a unique
865 nonnegative integer, and the root node id is 0. A database is
866 implemented as a hash table that maps a pair (SRC-NODE-ID .
867 EDGE-LABEL) to DEST-NODE-ID. It also holds a maximum node id used
868 in the table as a value for HASHKEY_MAX_NID. A value associated to
869 a node is recorded as a value for the node id.
871 A database also has a cache for past queries as a value for
872 HASHKEY_QUERY_CACHE. It is another hash table that maps
873 "NAME-STRING\0CLASS-STRING" to the result of the query. */
875 #define HASHKEY_MAX_NID (make_number (0))
876 #define HASHKEY_QUERY_CACHE (make_number (-1))
879 xrm_create_database ()
881 XrmDatabase database
;
883 database
= make_hash_table (Qequal
, make_number (DEFAULT_HASH_SIZE
),
884 make_float (DEFAULT_REHASH_SIZE
),
885 make_float (DEFAULT_REHASH_THRESHOLD
),
887 Fputhash (HASHKEY_MAX_NID
, make_number (0), database
);
888 Fputhash (HASHKEY_QUERY_CACHE
, Qnil
, database
);
894 xrm_q_put_resource (database
, quarks
, value
)
895 XrmDatabase database
;
896 Lisp_Object quarks
, value
;
898 struct Lisp_Hash_Table
*h
= XHASH_TABLE (database
);
901 Lisp_Object node_id
, key
;
903 max_nid
= XINT (Fgethash (HASHKEY_MAX_NID
, database
, Qnil
));
905 XSETINT (node_id
, 0);
906 for (; CONSP (quarks
); quarks
= XCDR (quarks
))
908 key
= Fcons (node_id
, XCAR (quarks
));
909 i
= hash_lookup (h
, key
, &hash_code
);
913 XSETINT (node_id
, max_nid
);
914 hash_put (h
, key
, node_id
, hash_code
);
917 node_id
= HASH_VALUE (h
, i
);
919 Fputhash (node_id
, value
, database
);
921 Fputhash (HASHKEY_MAX_NID
, make_number (max_nid
), database
);
922 Fputhash (HASHKEY_QUERY_CACHE
, Qnil
, database
);
925 /* Merge multiple resource entries specified by DATA into a resource
926 database DATABASE. DATA points to the head of a null-terminated
927 string consisting of multiple resource lines. It's like a
928 combination of XrmGetStringDatabase and XrmMergeDatabases. */
931 xrm_merge_string_database (database
, data
)
932 XrmDatabase database
;
935 Lisp_Object quarks_value
;
939 quarks_value
= parse_resource_line (&data
);
940 if (!NILP (quarks_value
))
941 xrm_q_put_resource (database
,
942 XCAR (quarks_value
), XCDR (quarks_value
));
947 xrm_q_get_resource_1 (database
, node_id
, quark_name
, quark_class
)
948 XrmDatabase database
;
949 Lisp_Object node_id
, quark_name
, quark_class
;
951 struct Lisp_Hash_Table
*h
= XHASH_TABLE (database
);
952 Lisp_Object key
, labels
[3], value
;
955 if (!CONSP (quark_name
))
956 return Fgethash (node_id
, database
, Qnil
);
958 /* First, try tight bindings */
959 labels
[0] = XCAR (quark_name
);
960 labels
[1] = XCAR (quark_class
);
961 labels
[2] = SINGLE_COMPONENT
;
963 key
= Fcons (node_id
, Qnil
);
964 for (k
= 0; k
< sizeof (labels
) / sizeof (*labels
); k
++)
966 XSETCDR (key
, labels
[k
]);
967 i
= hash_lookup (h
, key
, NULL
);
970 value
= xrm_q_get_resource_1 (database
, HASH_VALUE (h
, i
),
971 XCDR (quark_name
), XCDR (quark_class
));
977 /* Then, try loose bindings */
978 XSETCDR (key
, LOOSE_BINDING
);
979 i
= hash_lookup (h
, key
, NULL
);
982 value
= xrm_q_get_resource_1 (database
, HASH_VALUE (h
, i
),
983 quark_name
, quark_class
);
987 return xrm_q_get_resource_1 (database
, node_id
,
988 XCDR (quark_name
), XCDR (quark_class
));
995 xrm_q_get_resource (database
, quark_name
, quark_class
)
996 XrmDatabase database
;
997 Lisp_Object quark_name
, quark_class
;
999 return xrm_q_get_resource_1 (database
, make_number (0),
1000 quark_name
, quark_class
);
1003 /* Retrieve a resource value for the specified NAME and CLASS from the
1004 resource database DATABASE. It corresponds to XrmGetResource. */
1007 xrm_get_resource (database
, name
, class)
1008 XrmDatabase database
;
1011 Lisp_Object key
, query_cache
, quark_name
, quark_class
, tmp
;
1013 struct Lisp_Hash_Table
*h
;
1017 nc
= strlen (class);
1018 key
= make_uninit_string (nn
+ nc
+ 1);
1019 strcpy (SDATA (key
), name
);
1020 strncpy (SDATA (key
) + nn
+ 1, class, nc
);
1022 query_cache
= Fgethash (HASHKEY_QUERY_CACHE
, database
, Qnil
);
1023 if (NILP (query_cache
))
1025 query_cache
= make_hash_table (Qequal
, make_number (DEFAULT_HASH_SIZE
),
1026 make_float (DEFAULT_REHASH_SIZE
),
1027 make_float (DEFAULT_REHASH_THRESHOLD
),
1029 Fputhash (HASHKEY_QUERY_CACHE
, query_cache
, database
);
1031 h
= XHASH_TABLE (query_cache
);
1032 i
= hash_lookup (h
, key
, &hash_code
);
1034 return HASH_VALUE (h
, i
);
1036 quark_name
= parse_resource_name (&name
);
1039 for (tmp
= quark_name
, nn
= 0; CONSP (tmp
); tmp
= XCDR (tmp
), nn
++)
1040 if (!STRINGP (XCAR (tmp
)))
1043 quark_class
= parse_resource_name (&class);
1046 for (tmp
= quark_class
, nc
= 0; CONSP (tmp
); tmp
= XCDR (tmp
), nc
++)
1047 if (!STRINGP (XCAR (tmp
)))
1054 tmp
= xrm_q_get_resource (database
, quark_name
, quark_class
);
1055 hash_put (h
, key
, tmp
, hash_code
);
1060 #if TARGET_API_MAC_CARBON
1062 xrm_cfproperty_list_to_value (plist
)
1063 CFPropertyListRef plist
;
1065 CFTypeID type_id
= CFGetTypeID (plist
);
1067 if (type_id
== CFStringGetTypeID ())
1068 return cfstring_to_lisp (plist
);
1069 else if (type_id
== CFNumberGetTypeID ())
1072 Lisp_Object result
= Qnil
;
1074 string
= CFStringCreateWithFormat (NULL
, NULL
, CFSTR ("%@"), plist
);
1077 result
= cfstring_to_lisp (string
);
1082 else if (type_id
== CFBooleanGetTypeID ())
1083 return build_string (CFBooleanGetValue (plist
) ? "true" : "false");
1084 else if (type_id
== CFDataGetTypeID ())
1085 return cfdata_to_lisp (plist
);
1091 /* Create a new resource database from the preferences for the
1092 application APPLICATION. APPLICATION is either a string that
1093 specifies an application ID, or NULL that represents the current
1097 xrm_get_preference_database (application
)
1100 #if TARGET_API_MAC_CARBON
1101 CFStringRef app_id
, *keys
, user_doms
[2], host_doms
[2];
1102 CFMutableSetRef key_set
= NULL
;
1103 CFArrayRef key_array
;
1104 CFIndex index
, count
;
1106 XrmDatabase database
;
1107 Lisp_Object quarks
= Qnil
, value
= Qnil
;
1108 CFPropertyListRef plist
;
1110 struct gcpro gcpro1
, gcpro2
, gcpro3
;
1112 user_doms
[0] = kCFPreferencesCurrentUser
;
1113 user_doms
[1] = kCFPreferencesAnyUser
;
1114 host_doms
[0] = kCFPreferencesCurrentHost
;
1115 host_doms
[1] = kCFPreferencesAnyHost
;
1117 database
= xrm_create_database ();
1119 GCPRO3 (database
, quarks
, value
);
1123 app_id
= kCFPreferencesCurrentApplication
;
1126 app_id
= cfstring_create_with_utf8_cstring (application
);
1131 key_set
= CFSetCreateMutable (NULL
, 0, &kCFCopyStringSetCallBacks
);
1132 if (key_set
== NULL
)
1134 for (iu
= 0; iu
< sizeof (user_doms
) / sizeof (*user_doms
) ; iu
++)
1135 for (ih
= 0; ih
< sizeof (host_doms
) / sizeof (*host_doms
); ih
++)
1137 key_array
= CFPreferencesCopyKeyList (app_id
, user_doms
[iu
],
1141 count
= CFArrayGetCount (key_array
);
1142 for (index
= 0; index
< count
; index
++)
1143 CFSetAddValue (key_set
,
1144 CFArrayGetValueAtIndex (key_array
, index
));
1145 CFRelease (key_array
);
1149 count
= CFSetGetCount (key_set
);
1150 keys
= xmalloc (sizeof (CFStringRef
) * count
);
1153 CFSetGetValues (key_set
, (const void **)keys
);
1154 for (index
= 0; index
< count
; index
++)
1156 res_name
= SDATA (cfstring_to_lisp_nodecode (keys
[index
]));
1157 quarks
= parse_resource_name (&res_name
);
1158 if (!(NILP (quarks
) || *res_name
))
1160 plist
= CFPreferencesCopyAppValue (keys
[index
], app_id
);
1161 value
= xrm_cfproperty_list_to_value (plist
);
1164 xrm_q_put_resource (database
, quarks
, value
);
1171 CFRelease (key_set
);
1180 return xrm_create_database ();
1187 /* The following functions with "sys_" prefix are stubs to Unix
1188 functions that have already been implemented by CW or MPW. The
1189 calls to them in Emacs source course are #define'd to call the sys_
1190 versions by the header files s-mac.h. In these stubs pathnames are
1191 converted between their Unix and Mac forms. */
1194 /* Unix epoch is Jan 1, 1970 while Mac epoch is Jan 1, 1904: 66 years
1195 + 17 leap days. These are for adjusting time values returned by
1196 MacOS Toolbox functions. */
1198 #define MAC_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
1201 #if __MSL__ < 0x6000
1202 /* CW Pro 5 epoch is Jan 1, 1900 (aaarghhhhh!); remember, 1900 is not
1203 a leap year! This is for adjusting time_t values returned by MSL
1205 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 70 + 17) * 24 * 60 * 60)
1206 #else /* __MSL__ >= 0x6000 */
1207 /* CW changes Pro 6 to follow Unix! */
1208 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
1209 #endif /* __MSL__ >= 0x6000 */
1211 /* MPW library functions follow Unix (confused?). */
1212 #define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
1213 #else /* not __MRC__ */
1215 #endif /* not __MRC__ */
1218 /* Define our own stat function for both MrC and CW. The reason for
1219 doing this: "stat" is both the name of a struct and function name:
1220 can't use the same trick like that for sys_open, sys_close, etc. to
1221 redirect Emacs's calls to our own version that converts Unix style
1222 filenames to Mac style filename because all sorts of compilation
1223 errors will be generated if stat is #define'd to be sys_stat. */
1226 stat_noalias (const char *path
, struct stat
*buf
)
1228 char mac_pathname
[MAXPATHLEN
+1];
1231 if (posix_to_mac_pathname (path
, mac_pathname
, MAXPATHLEN
+1) == 0)
1234 c2pstr (mac_pathname
);
1235 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
1236 cipb
.hFileInfo
.ioVRefNum
= 0;
1237 cipb
.hFileInfo
.ioDirID
= 0;
1238 cipb
.hFileInfo
.ioFDirIndex
= 0;
1239 /* set to 0 to get information about specific dir or file */
1241 errno
= PBGetCatInfo (&cipb
, false);
1242 if (errno
== -43) /* -43: fnfErr defined in Errors.h */
1247 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* bit 4 = 1 for directories */
1249 buf
->st_mode
= S_IFDIR
| S_IREAD
| S_IEXEC
;
1251 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x1))
1252 buf
->st_mode
|= S_IWRITE
; /* bit 1 = 1 for locked files/directories */
1253 buf
->st_ino
= cipb
.dirInfo
.ioDrDirID
;
1254 buf
->st_dev
= cipb
.dirInfo
.ioVRefNum
;
1255 buf
->st_size
= cipb
.dirInfo
.ioDrNmFls
;
1256 /* size of dir = number of files and dirs */
1259 = cipb
.dirInfo
.ioDrMdDat
- MAC_UNIX_EPOCH_DIFF
;
1260 buf
->st_ctime
= cipb
.dirInfo
.ioDrCrDat
- MAC_UNIX_EPOCH_DIFF
;
1264 buf
->st_mode
= S_IFREG
| S_IREAD
;
1265 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x1))
1266 buf
->st_mode
|= S_IWRITE
; /* bit 1 = 1 for locked files/directories */
1267 if (cipb
.hFileInfo
.ioFlFndrInfo
.fdType
== 'APPL')
1268 buf
->st_mode
|= S_IEXEC
;
1269 buf
->st_ino
= cipb
.hFileInfo
.ioDirID
;
1270 buf
->st_dev
= cipb
.hFileInfo
.ioVRefNum
;
1271 buf
->st_size
= cipb
.hFileInfo
.ioFlLgLen
;
1274 = cipb
.hFileInfo
.ioFlMdDat
- MAC_UNIX_EPOCH_DIFF
;
1275 buf
->st_ctime
= cipb
.hFileInfo
.ioFlCrDat
- MAC_UNIX_EPOCH_DIFF
;
1278 if (cipb
.hFileInfo
.ioFlFndrInfo
.fdFlags
& 0x8000)
1280 /* identify alias files as symlinks */
1281 buf
->st_mode
&= ~S_IFREG
;
1282 buf
->st_mode
|= S_IFLNK
;
1286 buf
->st_uid
= getuid ();
1287 buf
->st_gid
= getgid ();
1295 lstat (const char *path
, struct stat
*buf
)
1298 char true_pathname
[MAXPATHLEN
+1];
1300 /* Try looking for the file without resolving aliases first. */
1301 if ((result
= stat_noalias (path
, buf
)) >= 0)
1304 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
1307 return stat_noalias (true_pathname
, buf
);
1312 stat (const char *path
, struct stat
*sb
)
1315 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
1318 if ((result
= stat_noalias (path
, sb
)) >= 0 &&
1319 ! (sb
->st_mode
& S_IFLNK
))
1322 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
1325 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
1328 fully_resolved_name
[len
] = '\0';
1329 /* in fact our readlink terminates strings */
1330 return lstat (fully_resolved_name
, sb
);
1333 return lstat (true_pathname
, sb
);
1338 /* CW defines fstat in stat.mac.c while MPW does not provide this
1339 function. Without the information of how to get from a file
1340 descriptor in MPW StdCLib to a Mac OS file spec, it should be hard
1341 to implement this function. Fortunately, there is only one place
1342 where this function is called in our configuration: in fileio.c,
1343 where only the st_dev and st_ino fields are used to determine
1344 whether two fildes point to different i-nodes to prevent copying
1345 a file onto itself equal. What we have here probably needs
1349 fstat (int fildes
, struct stat
*buf
)
1352 buf
->st_ino
= fildes
;
1353 buf
->st_mode
= S_IFREG
; /* added by T.I. for the copy-file */
1354 return 0; /* success */
1356 #endif /* __MRC__ */
1360 mkdir (const char *dirname
, int mode
)
1362 #pragma unused(mode)
1365 char true_pathname
[MAXPATHLEN
+1], mac_pathname
[MAXPATHLEN
+1];
1367 if (find_true_pathname (dirname
, true_pathname
, MAXPATHLEN
+1) == -1)
1370 if (posix_to_mac_pathname (true_pathname
, mac_pathname
, MAXPATHLEN
+1) == 0)
1373 c2pstr (mac_pathname
);
1374 hfpb
.ioNamePtr
= mac_pathname
;
1375 hfpb
.ioVRefNum
= 0; /* ignored unless name is invalid */
1376 hfpb
.ioDirID
= 0; /* parent is the root */
1378 errno
= PBDirCreate ((HParmBlkPtr
) &hfpb
, false);
1379 /* just return the Mac OSErr code for now */
1380 return errno
== noErr
? 0 : -1;
1385 sys_rmdir (const char *dirname
)
1388 char mac_pathname
[MAXPATHLEN
+1];
1390 if (posix_to_mac_pathname (dirname
, mac_pathname
, MAXPATHLEN
+1) == 0)
1393 c2pstr (mac_pathname
);
1394 hfpb
.ioNamePtr
= mac_pathname
;
1395 hfpb
.ioVRefNum
= 0; /* ignored unless name is invalid */
1396 hfpb
.ioDirID
= 0; /* parent is the root */
1398 errno
= PBHDelete ((HParmBlkPtr
) &hfpb
, false);
1399 return errno
== noErr
? 0 : -1;
1404 /* No implementation yet. */
1406 execvp (const char *path
, ...)
1410 #endif /* __MRC__ */
1414 utime (const char *path
, const struct utimbuf
*times
)
1416 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
1418 char mac_pathname
[MAXPATHLEN
+1];
1421 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
1424 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
1426 fully_resolved_name
[len
] = '\0';
1428 strcpy (fully_resolved_name
, true_pathname
);
1430 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
1433 c2pstr (mac_pathname
);
1434 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
1435 cipb
.hFileInfo
.ioVRefNum
= 0;
1436 cipb
.hFileInfo
.ioDirID
= 0;
1437 cipb
.hFileInfo
.ioFDirIndex
= 0;
1438 /* set to 0 to get information about specific dir or file */
1440 errno
= PBGetCatInfo (&cipb
, false);
1444 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* bit 4 = 1 for directories */
1447 cipb
.dirInfo
.ioDrMdDat
= times
->modtime
+ MAC_UNIX_EPOCH_DIFF
;
1449 GetDateTime (&cipb
.dirInfo
.ioDrMdDat
);
1454 cipb
.hFileInfo
.ioFlMdDat
= times
->modtime
+ MAC_UNIX_EPOCH_DIFF
;
1456 GetDateTime (&cipb
.hFileInfo
.ioFlMdDat
);
1459 errno
= PBSetCatInfo (&cipb
, false);
1460 return errno
== noErr
? 0 : -1;
1474 /* Like stat, but test for access mode in hfpb.ioFlAttrib */
1476 access (const char *path
, int mode
)
1478 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
1480 char mac_pathname
[MAXPATHLEN
+1];
1483 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
1486 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
1488 fully_resolved_name
[len
] = '\0';
1490 strcpy (fully_resolved_name
, true_pathname
);
1492 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
1495 c2pstr (mac_pathname
);
1496 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
1497 cipb
.hFileInfo
.ioVRefNum
= 0;
1498 cipb
.hFileInfo
.ioDirID
= 0;
1499 cipb
.hFileInfo
.ioFDirIndex
= 0;
1500 /* set to 0 to get information about specific dir or file */
1502 errno
= PBGetCatInfo (&cipb
, false);
1506 if (mode
== F_OK
) /* got this far, file exists */
1510 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* path refers to a directory */
1514 if (cipb
.hFileInfo
.ioFlFndrInfo
.fdType
== 'APPL')
1521 return (cipb
.hFileInfo
.ioFlAttrib
& 0x1) ? -1 : 0;
1522 /* don't allow if lock bit is on */
1528 #define DEV_NULL_FD 0x10000
1532 sys_open (const char *path
, int oflag
)
1534 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
1536 char mac_pathname
[MAXPATHLEN
+1];
1538 if (strcmp (path
, "/dev/null") == 0)
1539 return DEV_NULL_FD
; /* some bogus fd to be ignored in write */
1541 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
1544 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
1546 fully_resolved_name
[len
] = '\0';
1548 strcpy (fully_resolved_name
, true_pathname
);
1550 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
1555 int res
= open (mac_pathname
, oflag
);
1556 /* if (oflag == O_WRONLY || oflag == O_RDWR) */
1557 if (oflag
& O_CREAT
)
1558 fsetfileinfo (mac_pathname
, 'EMAx', 'TEXT');
1560 #else /* not __MRC__ */
1561 return open (mac_pathname
, oflag
);
1562 #endif /* not __MRC__ */
1569 sys_creat (const char *path
, mode_t mode
)
1571 char true_pathname
[MAXPATHLEN
+1];
1573 char mac_pathname
[MAXPATHLEN
+1];
1575 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
1578 if (!posix_to_mac_pathname (true_pathname
, mac_pathname
, MAXPATHLEN
+1))
1583 int result
= creat (mac_pathname
);
1584 fsetfileinfo (mac_pathname
, 'EMAx', 'TEXT');
1586 #else /* not __MRC__ */
1587 return creat (mac_pathname
, mode
);
1588 #endif /* not __MRC__ */
1595 sys_unlink (const char *path
)
1597 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
1599 char mac_pathname
[MAXPATHLEN
+1];
1601 if (find_true_pathname (path
, true_pathname
, MAXPATHLEN
+1) == -1)
1604 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
1606 fully_resolved_name
[len
] = '\0';
1608 strcpy (fully_resolved_name
, true_pathname
);
1610 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
1613 return unlink (mac_pathname
);
1619 sys_read (int fildes
, char *buf
, int count
)
1621 if (fildes
== 0) /* this should not be used for console input */
1624 #if __MSL__ >= 0x6000
1625 return _read (fildes
, buf
, count
);
1627 return read (fildes
, buf
, count
);
1634 sys_write (int fildes
, const char *buf
, int count
)
1636 if (fildes
== DEV_NULL_FD
)
1639 #if __MSL__ >= 0x6000
1640 return _write (fildes
, buf
, count
);
1642 return write (fildes
, buf
, count
);
1649 sys_rename (const char * old_name
, const char * new_name
)
1651 char true_old_pathname
[MAXPATHLEN
+1], true_new_pathname
[MAXPATHLEN
+1];
1652 char fully_resolved_old_name
[MAXPATHLEN
+1];
1654 char mac_old_name
[MAXPATHLEN
+1], mac_new_name
[MAXPATHLEN
+1];
1656 if (find_true_pathname (old_name
, true_old_pathname
, MAXPATHLEN
+1) == -1)
1659 len
= readlink (true_old_pathname
, fully_resolved_old_name
, MAXPATHLEN
);
1661 fully_resolved_old_name
[len
] = '\0';
1663 strcpy (fully_resolved_old_name
, true_old_pathname
);
1665 if (find_true_pathname (new_name
, true_new_pathname
, MAXPATHLEN
+1) == -1)
1668 if (strcmp (fully_resolved_old_name
, true_new_pathname
) == 0)
1671 if (!posix_to_mac_pathname (fully_resolved_old_name
,
1676 if (!posix_to_mac_pathname(true_new_pathname
, mac_new_name
, MAXPATHLEN
+1))
1679 /* If a file with new_name already exists, rename deletes the old
1680 file in Unix. CW version fails in these situation. So we add a
1681 call to unlink here. */
1682 (void) unlink (mac_new_name
);
1684 return rename (mac_old_name
, mac_new_name
);
1689 extern FILE *fopen (const char *name
, const char *mode
);
1691 sys_fopen (const char *name
, const char *mode
)
1693 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
1695 char mac_pathname
[MAXPATHLEN
+1];
1697 if (find_true_pathname (name
, true_pathname
, MAXPATHLEN
+1) == -1)
1700 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
1702 fully_resolved_name
[len
] = '\0';
1704 strcpy (fully_resolved_name
, true_pathname
);
1706 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
1711 if (mode
[0] == 'w' || mode
[0] == 'a')
1712 fsetfileinfo (mac_pathname
, 'EMAx', 'TEXT');
1713 #endif /* not __MRC__ */
1714 return fopen (mac_pathname
, mode
);
1719 #include "keyboard.h"
1720 extern Boolean
mac_wait_next_event (EventRecord
*, UInt32
, Boolean
);
1723 select (n
, rfds
, wfds
, efds
, timeout
)
1728 struct timeval
*timeout
;
1731 #if TARGET_API_MAC_CARBON
1732 EventTimeout timeout_sec
=
1734 ? (EMACS_SECS (*timeout
) * kEventDurationSecond
1735 + EMACS_USECS (*timeout
) * kEventDurationMicrosecond
)
1736 : kEventDurationForever
);
1739 err
= ReceiveNextEvent (0, NULL
, timeout_sec
, kEventLeaveInQueue
, NULL
);
1741 #else /* not TARGET_API_MAC_CARBON */
1743 UInt32 sleep_time
= EMACS_SECS (*timeout
) * 60 +
1744 ((EMACS_USECS (*timeout
) * 60) / 1000000);
1746 /* Can only handle wait for keyboard input. */
1747 if (n
> 1 || wfds
|| efds
)
1750 /* Also return true if an event other than a keyDown has occurred.
1751 This causes kbd_buffer_get_event in keyboard.c to call
1752 read_avail_input which in turn calls XTread_socket to poll for
1753 these events. Otherwise these never get processed except but a
1754 very slow poll timer. */
1755 if (mac_wait_next_event (&e
, sleep_time
, false))
1758 err
= -9875; /* eventLoopTimedOutErr */
1759 #endif /* not TARGET_API_MAC_CARBON */
1761 if (FD_ISSET (0, rfds
))
1772 if (input_polling_used ())
1774 /* It could be confusing if a real alarm arrives while
1775 processing the fake one. Turn it off and let the
1776 handler reset it. */
1777 extern void poll_for_input_1
P_ ((void));
1778 int old_poll_suppress_count
= poll_suppress_count
;
1779 poll_suppress_count
= 1;
1780 poll_for_input_1 ();
1781 poll_suppress_count
= old_poll_suppress_count
;
1791 /* Simulation of SIGALRM. The stub for function signal stores the
1792 signal handler function in alarm_signal_func if a SIGALRM is
1796 #include "syssignal.h"
1798 static TMTask mac_atimer_task
;
1800 static QElemPtr mac_atimer_qlink
= (QElemPtr
) &mac_atimer_task
;
1802 static int signal_mask
= 0;
1805 __sigfun alarm_signal_func
= (__sigfun
) 0;
1807 __signal_func_ptr alarm_signal_func
= (__signal_func_ptr
) 0;
1808 #else /* not __MRC__ and not __MWERKS__ */
1810 #endif /* not __MRC__ and not __MWERKS__ */
1814 extern __sigfun
signal (int signal
, __sigfun signal_func
);
1816 sys_signal (int signal_num
, __sigfun signal_func
)
1818 extern __signal_func_ptr
signal (int signal
, __signal_func_ptr signal_func
);
1820 sys_signal (int signal_num
, __signal_func_ptr signal_func
)
1821 #else /* not __MRC__ and not __MWERKS__ */
1823 #endif /* not __MRC__ and not __MWERKS__ */
1825 if (signal_num
!= SIGALRM
)
1826 return signal (signal_num
, signal_func
);
1830 __sigfun old_signal_func
;
1832 __signal_func_ptr old_signal_func
;
1836 old_signal_func
= alarm_signal_func
;
1837 alarm_signal_func
= signal_func
;
1838 return old_signal_func
;
1844 mac_atimer_handler (qlink
)
1847 if (alarm_signal_func
)
1848 (alarm_signal_func
) (SIGALRM
);
1853 set_mac_atimer (count
)
1856 static TimerUPP mac_atimer_handlerUPP
= NULL
;
1858 if (mac_atimer_handlerUPP
== NULL
)
1859 mac_atimer_handlerUPP
= NewTimerUPP (mac_atimer_handler
);
1860 mac_atimer_task
.tmCount
= 0;
1861 mac_atimer_task
.tmAddr
= mac_atimer_handlerUPP
;
1862 mac_atimer_qlink
= (QElemPtr
) &mac_atimer_task
;
1863 InsTime (mac_atimer_qlink
);
1865 PrimeTime (mac_atimer_qlink
, count
);
1870 remove_mac_atimer (remaining_count
)
1871 long *remaining_count
;
1873 if (mac_atimer_qlink
)
1875 RmvTime (mac_atimer_qlink
);
1876 if (remaining_count
)
1877 *remaining_count
= mac_atimer_task
.tmCount
;
1878 mac_atimer_qlink
= NULL
;
1890 int old_mask
= signal_mask
;
1892 signal_mask
|= mask
;
1894 if ((old_mask
^ signal_mask
) & sigmask (SIGALRM
))
1895 remove_mac_atimer (NULL
);
1902 sigsetmask (int mask
)
1904 int old_mask
= signal_mask
;
1908 if ((old_mask
^ signal_mask
) & sigmask (SIGALRM
))
1909 if (signal_mask
& sigmask (SIGALRM
))
1910 remove_mac_atimer (NULL
);
1912 set_mac_atimer (mac_atimer_task
.tmCount
);
1921 long remaining_count
;
1923 if (remove_mac_atimer (&remaining_count
) == 0)
1925 set_mac_atimer (seconds
* 1000);
1927 return remaining_count
/ 1000;
1931 mac_atimer_task
.tmCount
= seconds
* 1000;
1939 setitimer (which
, value
, ovalue
)
1941 const struct itimerval
*value
;
1942 struct itimerval
*ovalue
;
1944 long remaining_count
;
1945 long count
= (EMACS_SECS (value
->it_value
) * 1000
1946 + (EMACS_USECS (value
->it_value
) + 999) / 1000);
1948 if (remove_mac_atimer (&remaining_count
) == 0)
1952 bzero (ovalue
, sizeof (*ovalue
));
1953 EMACS_SET_SECS_USECS (ovalue
->it_value
, remaining_count
/ 1000,
1954 (remaining_count
% 1000) * 1000);
1956 set_mac_atimer (count
);
1959 mac_atimer_task
.tmCount
= count
;
1965 /* gettimeofday should return the amount of time (in a timeval
1966 structure) since midnight today. The toolbox function Microseconds
1967 returns the number of microseconds (in a UnsignedWide value) since
1968 the machine was booted. Also making this complicated is WideAdd,
1969 WideSubtract, etc. take wide values. */
1976 static wide wall_clock_at_epoch
, clicks_at_epoch
;
1977 UnsignedWide uw_microseconds
;
1978 wide w_microseconds
;
1979 time_t sys_time (time_t *);
1981 /* If this function is called for the first time, record the number
1982 of seconds since midnight and the number of microseconds since
1983 boot at the time of this first call. */
1988 systime
= sys_time (NULL
);
1989 /* Store microseconds since midnight in wall_clock_at_epoch. */
1990 WideMultiply (systime
, 1000000L, &wall_clock_at_epoch
);
1991 Microseconds (&uw_microseconds
);
1992 /* Store microseconds since boot in clicks_at_epoch. */
1993 clicks_at_epoch
.hi
= uw_microseconds
.hi
;
1994 clicks_at_epoch
.lo
= uw_microseconds
.lo
;
1997 /* Get time since boot */
1998 Microseconds (&uw_microseconds
);
2000 /* Convert to time since midnight*/
2001 w_microseconds
.hi
= uw_microseconds
.hi
;
2002 w_microseconds
.lo
= uw_microseconds
.lo
;
2003 WideSubtract (&w_microseconds
, &clicks_at_epoch
);
2004 WideAdd (&w_microseconds
, &wall_clock_at_epoch
);
2005 tp
->tv_sec
= WideDivide (&w_microseconds
, 1000000L, &tp
->tv_usec
);
2013 sleep (unsigned int seconds
)
2015 unsigned long time_up
;
2018 time_up
= TickCount () + seconds
* 60;
2019 while (TickCount () < time_up
)
2021 /* Accept no event; just wait. by T.I. */
2022 WaitNextEvent (0, &e
, 30, NULL
);
2027 #endif /* __MRC__ */
2030 /* The time functions adjust time values according to the difference
2031 between the Unix and CW epoches. */
2034 extern struct tm
*gmtime (const time_t *);
2036 sys_gmtime (const time_t *timer
)
2038 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
2040 return gmtime (&unix_time
);
2045 extern struct tm
*localtime (const time_t *);
2047 sys_localtime (const time_t *timer
)
2049 #if __MSL__ >= 0x6000
2050 time_t unix_time
= *timer
;
2052 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
2055 return localtime (&unix_time
);
2060 extern char *ctime (const time_t *);
2062 sys_ctime (const time_t *timer
)
2064 #if __MSL__ >= 0x6000
2065 time_t unix_time
= *timer
;
2067 time_t unix_time
= *timer
+ CW_OR_MPW_UNIX_EPOCH_DIFF
;
2070 return ctime (&unix_time
);
2075 extern time_t time (time_t *);
2077 sys_time (time_t *timer
)
2079 #if __MSL__ >= 0x6000
2080 time_t mac_time
= time (NULL
);
2082 time_t mac_time
= time (NULL
) - CW_OR_MPW_UNIX_EPOCH_DIFF
;
2092 /* no subprocesses, empty wait */
2102 croak (char *badfunc
)
2104 printf ("%s not yet implemented\r\n", badfunc
);
2110 mktemp (char *template)
2115 len
= strlen (template);
2117 while (k
>= 0 && template[k
] == 'X')
2120 k
++; /* make k index of first 'X' */
2124 /* Zero filled, number of digits equal to the number of X's. */
2125 sprintf (&template[k
], "%0*d", len
-k
, seqnum
++);
2134 /* Emulate getpwuid, getpwnam and others. */
2136 #define PASSWD_FIELD_SIZE 256
2138 static char my_passwd_name
[PASSWD_FIELD_SIZE
];
2139 static char my_passwd_dir
[MAXPATHLEN
+1];
2141 static struct passwd my_passwd
=
2147 static struct group my_group
=
2149 /* There are no groups on the mac, so we just return "root" as the
2155 /* Initialized by main () in macterm.c to pathname of emacs directory. */
2157 char emacs_passwd_dir
[MAXPATHLEN
+1];
2163 init_emacs_passwd_dir ()
2167 if (getwd (emacs_passwd_dir
) && getwd (my_passwd_dir
))
2169 /* Need pathname of first ancestor that begins with "emacs"
2170 since Mac emacs application is somewhere in the emacs-*
2172 int len
= strlen (emacs_passwd_dir
);
2174 /* j points to the "/" following the directory name being
2177 while (i
>= 0 && !found
)
2179 while (i
>= 0 && emacs_passwd_dir
[i
] != '/')
2181 if (emacs_passwd_dir
[i
] == '/' && i
+5 < len
)
2182 found
= (strncmp (&(emacs_passwd_dir
[i
+1]), "emacs", 5) == 0);
2184 emacs_passwd_dir
[j
+1] = '\0';
2195 /* Setting to "/" probably won't work but set it to something
2197 strcpy (emacs_passwd_dir
, "/");
2198 strcpy (my_passwd_dir
, "/");
2203 static struct passwd emacs_passwd
=
2209 static int my_passwd_inited
= 0;
2217 /* Note: my_passwd_dir initialized in int_emacs_passwd_dir to
2218 directory where Emacs was started. */
2220 owner_name
= (char **) GetResource ('STR ',-16096);
2224 BlockMove ((unsigned char *) *owner_name
,
2225 (unsigned char *) my_passwd_name
,
2227 HUnlock (owner_name
);
2228 p2cstr ((unsigned char *) my_passwd_name
);
2231 my_passwd_name
[0] = 0;
2236 getpwuid (uid_t uid
)
2238 if (!my_passwd_inited
)
2241 my_passwd_inited
= 1;
2249 getgrgid (gid_t gid
)
2256 getpwnam (const char *name
)
2258 if (strcmp (name
, "emacs") == 0)
2259 return &emacs_passwd
;
2261 if (!my_passwd_inited
)
2264 my_passwd_inited
= 1;
2271 /* The functions fork, kill, sigsetmask, sigblock, request_sigio,
2272 setpgrp, setpriority, and unrequest_sigio are defined to be empty
2293 error ("Can't spawn subshell");
2298 request_sigio (void)
2304 unrequest_sigio (void)
2319 pipe (int _fildes
[2])
2326 /* Hard and symbolic links. */
2329 symlink (const char *name1
, const char *name2
)
2337 link (const char *name1
, const char *name2
)
2343 #endif /* ! MAC_OSX */
2345 /* Determine the path name of the file specified by VREFNUM, DIRID,
2346 and NAME and place that in the buffer PATH of length
2349 path_from_vol_dir_name (char *path
, int man_path_len
, short vol_ref_num
,
2350 long dir_id
, ConstStr255Param name
)
2356 if (strlen (name
) > man_path_len
)
2359 memcpy (dir_name
, name
, name
[0]+1);
2360 memcpy (path
, name
, name
[0]+1);
2363 cipb
.dirInfo
.ioDrParID
= dir_id
;
2364 cipb
.dirInfo
.ioNamePtr
= dir_name
;
2368 cipb
.dirInfo
.ioVRefNum
= vol_ref_num
;
2369 cipb
.dirInfo
.ioFDirIndex
= -1;
2370 cipb
.dirInfo
.ioDrDirID
= cipb
.dirInfo
.ioDrParID
;
2371 /* go up to parent each time */
2373 err
= PBGetCatInfo (&cipb
, false);
2378 if (strlen (dir_name
) + strlen (path
) + 1 >= man_path_len
)
2381 strcat (dir_name
, ":");
2382 strcat (dir_name
, path
);
2383 /* attach to front since we're going up directory tree */
2384 strcpy (path
, dir_name
);
2386 while (cipb
.dirInfo
.ioDrDirID
!= fsRtDirID
);
2387 /* stop when we see the volume's root directory */
2389 return 1; /* success */
2394 posix_pathname_to_fsspec (ufn
, fs
)
2398 Str255 mac_pathname
;
2400 if (posix_to_mac_pathname (ufn
, mac_pathname
, sizeof (mac_pathname
)) == 0)
2404 c2pstr (mac_pathname
);
2405 return FSMakeFSSpec (0, 0, mac_pathname
, fs
);
2410 fsspec_to_posix_pathname (fs
, ufn
, ufnbuflen
)
2415 char mac_pathname
[MAXPATHLEN
];
2417 if (path_from_vol_dir_name (mac_pathname
, sizeof (mac_pathname
) - 1,
2418 fs
->vRefNum
, fs
->parID
, fs
->name
)
2419 && mac_to_posix_pathname (mac_pathname
, ufn
, ufnbuflen
))
2428 readlink (const char *path
, char *buf
, int bufsiz
)
2430 char mac_sym_link_name
[MAXPATHLEN
+1];
2433 Boolean target_is_folder
, was_aliased
;
2434 Str255 directory_name
, mac_pathname
;
2437 if (posix_to_mac_pathname (path
, mac_sym_link_name
, MAXPATHLEN
+1) == 0)
2440 c2pstr (mac_sym_link_name
);
2441 err
= FSMakeFSSpec (0, 0, mac_sym_link_name
, &fsspec
);
2448 err
= ResolveAliasFile (&fsspec
, true, &target_is_folder
, &was_aliased
);
2449 if (err
!= noErr
|| !was_aliased
)
2455 if (path_from_vol_dir_name (mac_pathname
, 255, fsspec
.vRefNum
, fsspec
.parID
,
2462 if (mac_to_posix_pathname (mac_pathname
, buf
, bufsiz
) == 0)
2468 return strlen (buf
);
2472 /* Convert a path to one with aliases fully expanded. */
2475 find_true_pathname (const char *path
, char *buf
, int bufsiz
)
2477 char *q
, temp
[MAXPATHLEN
+1];
2481 if (bufsiz
<= 0 || path
== 0 || path
[0] == '\0')
2488 q
= strchr (p
+ 1, '/');
2490 q
= strchr (p
, '/');
2491 len
= 0; /* loop may not be entered, e.g., for "/" */
2496 strncat (temp
, p
, q
- p
);
2497 len
= readlink (temp
, buf
, bufsiz
);
2500 if (strlen (temp
) + 1 > bufsiz
)
2510 if (len
+ strlen (p
) + 1 >= bufsiz
)
2514 return len
+ strlen (p
);
2519 umask (mode_t numask
)
2521 static mode_t mask
= 022;
2522 mode_t oldmask
= mask
;
2529 chmod (const char *path
, mode_t mode
)
2531 /* say it always succeed for now */
2537 fchmod (int fd
, mode_t mode
)
2539 /* say it always succeed for now */
2545 fchown (int fd
, uid_t owner
, gid_t group
)
2547 /* say it always succeed for now */
2556 return fcntl (oldd
, F_DUPFD
, 0);
2558 /* current implementation of fcntl in fcntl.mac.c simply returns old
2560 return fcntl (oldd
, F_DUPFD
);
2567 /* This is from the original sysdep.c. Emulate BSD dup2. First close
2568 newd if it already exists. Then, attempt to dup oldd. If not
2569 successful, call dup2 recursively until we are, then close the
2570 unsuccessful ones. */
2573 dup2 (int oldd
, int newd
)
2584 ret
= dup2 (oldd
, newd
);
2590 /* let it fail for now */
2607 ioctl (int d
, int request
, void *argp
)
2617 if (fildes
>=0 && fildes
<= 2)
2650 #endif /* __MRC__ */
2654 #if __MSL__ < 0x6000
2662 #endif /* __MWERKS__ */
2664 #endif /* ! MAC_OSX */
2667 /* Return the path to the directory in which Emacs can create
2668 temporary files. The MacOS "temporary items" directory cannot be
2669 used because it removes the file written by a process when it
2670 exits. In that sense it's more like "/dev/null" than "/tmp" (but
2671 again not exactly). And of course Emacs needs to read back the
2672 files written by its subprocesses. So here we write the files to a
2673 directory "Emacs" in the Preferences Folder. This directory is
2674 created if it does not exist. */
2677 get_temp_dir_name ()
2679 static char *temp_dir_name
= NULL
;
2683 Str255 dir_name
, full_path
;
2685 char unix_dir_name
[MAXPATHLEN
+1];
2688 /* Cache directory name with pointer temp_dir_name.
2689 Look for it only the first time. */
2692 err
= FindFolder (kOnSystemDisk
, kPreferencesFolderType
, kCreateFolder
,
2693 &vol_ref_num
, &dir_id
);
2697 if (!path_from_vol_dir_name (full_path
, 255, vol_ref_num
, dir_id
, "\p"))
2700 if (strlen (full_path
) + 6 <= MAXPATHLEN
)
2701 strcat (full_path
, "Emacs:");
2705 if (!mac_to_posix_pathname (full_path
, unix_dir_name
, MAXPATHLEN
+1))
2708 dir
= opendir (unix_dir_name
); /* check whether temp directory exists */
2711 else if (mkdir (unix_dir_name
, 0700) != 0) /* create it if not */
2714 temp_dir_name
= (char *) malloc (strlen (unix_dir_name
) + 1);
2715 strcpy (temp_dir_name
, unix_dir_name
);
2718 return temp_dir_name
;
2723 /* Allocate and construct an array of pointers to strings from a list
2724 of strings stored in a 'STR#' resource. The returned pointer array
2725 is stored in the style of argv and environ: if the 'STR#' resource
2726 contains numString strings, a pointer array with numString+1
2727 elements is returned in which the last entry contains a null
2728 pointer. The pointer to the pointer array is passed by pointer in
2729 parameter t. The resource ID of the 'STR#' resource is passed in
2730 parameter StringListID.
2734 get_string_list (char ***t
, short string_list_id
)
2740 h
= GetResource ('STR#', string_list_id
);
2745 num_strings
= * (short *) p
;
2747 *t
= (char **) malloc (sizeof (char *) * (num_strings
+ 1));
2748 for (i
= 0; i
< num_strings
; i
++)
2750 short length
= *p
++;
2751 (*t
)[i
] = (char *) malloc (length
+ 1);
2752 strncpy ((*t
)[i
], p
, length
);
2753 (*t
)[i
][length
] = '\0';
2756 (*t
)[num_strings
] = 0;
2761 /* Return no string in case GetResource fails. Bug fixed by
2762 Ikegami Tsutomu. Caused MPW build to crash without sym -on
2763 option (no sym -on implies -opt local). */
2764 *t
= (char **) malloc (sizeof (char *));
2771 get_path_to_system_folder ()
2776 Str255 dir_name
, full_path
;
2778 static char system_folder_unix_name
[MAXPATHLEN
+1];
2781 err
= FindFolder (kOnSystemDisk
, kSystemFolderType
, kDontCreateFolder
,
2782 &vol_ref_num
, &dir_id
);
2786 if (!path_from_vol_dir_name (full_path
, 255, vol_ref_num
, dir_id
, "\p"))
2789 if (!mac_to_posix_pathname (full_path
, system_folder_unix_name
,
2793 return system_folder_unix_name
;
2799 #define ENVIRON_STRING_LIST_ID 128
2801 /* Get environment variable definitions from STR# resource. */
2808 get_string_list (&environ
, ENVIRON_STRING_LIST_ID
);
2814 /* Make HOME directory the one Emacs starts up in if not specified
2816 if (getenv ("HOME") == NULL
)
2818 environ
= (char **) realloc (environ
, sizeof (char *) * (i
+ 2));
2821 environ
[i
] = (char *) malloc (strlen (my_passwd_dir
) + 6);
2824 strcpy (environ
[i
], "HOME=");
2825 strcat (environ
[i
], my_passwd_dir
);
2832 /* Make HOME directory the one Emacs starts up in if not specified
2834 if (getenv ("MAIL") == NULL
)
2836 environ
= (char **) realloc (environ
, sizeof (char *) * (i
+ 2));
2839 char * path_to_system_folder
= get_path_to_system_folder ();
2840 environ
[i
] = (char *) malloc (strlen (path_to_system_folder
) + 22);
2843 strcpy (environ
[i
], "MAIL=");
2844 strcat (environ
[i
], path_to_system_folder
);
2845 strcat (environ
[i
], "Eudora Folder/In");
2853 /* Return the value of the environment variable NAME. */
2856 getenv (const char *name
)
2858 int length
= strlen(name
);
2861 for (e
= environ
; *e
!= 0; e
++)
2862 if (strncmp(*e
, name
, length
) == 0 && (*e
)[length
] == '=')
2863 return &(*e
)[length
+ 1];
2865 if (strcmp (name
, "TMPDIR") == 0)
2866 return get_temp_dir_name ();
2873 /* see Interfaces&Libraries:Interfaces:CIncludes:signal.h */
2874 char *sys_siglist
[] =
2876 "Zero is not a signal!!!",
2878 "Interactive user interrupt", /* 2 */ "?",
2879 "Floating point exception", /* 4 */ "?", "?", "?",
2880 "Illegal instruction", /* 8 */ "?", "?", "?", "?", "?", "?", "?",
2881 "Segment violation", /* 16 */ "?", "?", "?", "?", "?", "?", "?",
2882 "?", "?", "?", "?", "?", "?", "?", "?",
2886 char *sys_siglist
[] =
2888 "Zero is not a signal!!!",
2890 "Floating point exception",
2891 "Illegal instruction",
2892 "Interactive user interrupt",
2893 "Segment violation",
2896 #else /* not __MRC__ and not __MWERKS__ */
2898 #endif /* not __MRC__ and not __MWERKS__ */
2901 #include <utsname.h>
2904 uname (struct utsname
*name
)
2907 system_name
= GetString (-16413); /* IM - Resource Manager Reference */
2910 BlockMove (*system_name
, name
->nodename
, (*system_name
)[0]+1);
2911 p2cstr (name
->nodename
);
2919 /* Event class of HLE sent to subprocess. */
2920 const OSType kEmacsSubprocessSend
= 'ESND';
2922 /* Event class of HLE sent back from subprocess. */
2923 const OSType kEmacsSubprocessReply
= 'ERPY';
2927 mystrchr (char *s
, char c
)
2929 while (*s
&& *s
!= c
)
2957 mystrcpy (char *to
, char *from
)
2969 /* Start a Mac subprocess. Arguments for it is passed in argv (null
2970 terminated). The process should run with the default directory
2971 "workdir", read input from "infn", and write output and error to
2972 "outfn" and "errfn", resp. The Process Manager call
2973 LaunchApplication is used to start the subprocess. We use high
2974 level events as the mechanism to pass arguments to the subprocess
2975 and to make Emacs wait for the subprocess to terminate and pass
2976 back a result code. The bulk of the code here packs the arguments
2977 into one message to be passed together with the high level event.
2978 Emacs also sometimes starts a subprocess using a shell to perform
2979 wildcard filename expansion. Since we don't really have a shell on
2980 the Mac, this case is detected and the starting of the shell is
2981 by-passed. We really need to add code here to do filename
2982 expansion to support such functionality. */
2985 run_mac_command (argv
, workdir
, infn
, outfn
, errfn
)
2986 unsigned char **argv
;
2987 const char *workdir
;
2988 const char *infn
, *outfn
, *errfn
;
2990 #if TARGET_API_MAC_CARBON
2992 #else /* not TARGET_API_MAC_CARBON */
2993 char macappname
[MAXPATHLEN
+1], macworkdir
[MAXPATHLEN
+1];
2994 char macinfn
[MAXPATHLEN
+1], macoutfn
[MAXPATHLEN
+1], macerrfn
[MAXPATHLEN
+1];
2995 int paramlen
, argc
, newargc
, j
, retries
;
2996 char **newargv
, *param
, *p
;
2999 LaunchParamBlockRec lpbr
;
3000 EventRecord send_event
, reply_event
;
3001 RgnHandle cursor_region_handle
;
3003 unsigned long ref_con
, len
;
3005 if (posix_to_mac_pathname (workdir
, macworkdir
, MAXPATHLEN
+1) == 0)
3007 if (posix_to_mac_pathname (infn
, macinfn
, MAXPATHLEN
+1) == 0)
3009 if (posix_to_mac_pathname (outfn
, macoutfn
, MAXPATHLEN
+1) == 0)
3011 if (posix_to_mac_pathname (errfn
, macerrfn
, MAXPATHLEN
+1) == 0)
3014 paramlen
= strlen (macworkdir
) + strlen (macinfn
) + strlen (macoutfn
)
3015 + strlen (macerrfn
) + 4; /* count nulls at end of strings */
3024 /* If a subprocess is invoked with a shell, we receive 3 arguments
3025 of the form: "<path to emacs bins>/sh" "-c" "<path to emacs
3026 bins>/<command> <command args>" */
3027 j
= strlen (argv
[0]);
3028 if (j
>= 3 && strcmp (argv
[0]+j
-3, "/sh") == 0
3029 && argc
== 3 && strcmp (argv
[1], "-c") == 0)
3031 char *command
, *t
, tempmacpathname
[MAXPATHLEN
+1];
3033 /* The arguments for the command in argv[2] are separated by
3034 spaces. Count them and put the count in newargc. */
3035 command
= (char *) alloca (strlen (argv
[2])+2);
3036 strcpy (command
, argv
[2]);
3037 if (command
[strlen (command
) - 1] != ' ')
3038 strcat (command
, " ");
3042 t
= mystrchr (t
, ' ');
3046 t
= mystrchr (t
+1, ' ');
3049 newargv
= (char **) alloca (sizeof (char *) * newargc
);
3052 for (j
= 0; j
< newargc
; j
++)
3054 newargv
[j
] = (char *) alloca (strlen (t
) + 1);
3055 mystrcpy (newargv
[j
], t
);
3058 paramlen
+= strlen (newargv
[j
]) + 1;
3061 if (strncmp (newargv
[0], "~emacs/", 7) == 0)
3063 if (posix_to_mac_pathname (newargv
[0], tempmacpathname
, MAXPATHLEN
+1)
3068 { /* sometimes Emacs call "sh" without a path for the command */
3070 char *t
= (char *) alloca (strlen (newargv
[0]) + 7 + 1);
3071 strcpy (t
, "~emacs/");
3072 strcat (t
, newargv
[0]);
3075 openp (Vexec_path
, build_string (newargv
[0]), Vexec_suffixes
, &path
,
3076 make_number (X_OK
));
3080 if (posix_to_mac_pathname (SDATA (path
), tempmacpathname
,
3084 strcpy (macappname
, tempmacpathname
);
3088 if (posix_to_mac_pathname (argv
[0], macappname
, MAXPATHLEN
+1) == 0)
3091 newargv
= (char **) alloca (sizeof (char *) * argc
);
3093 for (j
= 1; j
< argc
; j
++)
3095 if (strncmp (argv
[j
], "~emacs/", 7) == 0)
3097 char *t
= strchr (argv
[j
], ' ');
3100 char tempcmdname
[MAXPATHLEN
+1], tempmaccmdname
[MAXPATHLEN
+1];
3101 strncpy (tempcmdname
, argv
[j
], t
-argv
[j
]);
3102 tempcmdname
[t
-argv
[j
]] = '\0';
3103 if (posix_to_mac_pathname (tempcmdname
, tempmaccmdname
,
3106 newargv
[j
] = (char *) alloca (strlen (tempmaccmdname
)
3108 strcpy (newargv
[j
], tempmaccmdname
);
3109 strcat (newargv
[j
], t
);
3113 char tempmaccmdname
[MAXPATHLEN
+1];
3114 if (posix_to_mac_pathname (argv
[j
], tempmaccmdname
,
3117 newargv
[j
] = (char *) alloca (strlen (tempmaccmdname
)+1);
3118 strcpy (newargv
[j
], tempmaccmdname
);
3122 newargv
[j
] = argv
[j
];
3123 paramlen
+= strlen (newargv
[j
]) + 1;
3127 /* After expanding all the arguments, we now know the length of the
3128 parameter block to be sent to the subprocess as a message
3129 attached to the HLE. */
3130 param
= (char *) malloc (paramlen
+ 1);
3136 /* first byte of message contains number of arguments for command */
3137 strcpy (p
, macworkdir
);
3138 p
+= strlen (macworkdir
);
3140 /* null terminate strings sent so it's possible to use strcpy over there */
3141 strcpy (p
, macinfn
);
3142 p
+= strlen (macinfn
);
3144 strcpy (p
, macoutfn
);
3145 p
+= strlen (macoutfn
);
3147 strcpy (p
, macerrfn
);
3148 p
+= strlen (macerrfn
);
3150 for (j
= 1; j
< newargc
; j
++)
3152 strcpy (p
, newargv
[j
]);
3153 p
+= strlen (newargv
[j
]);
3157 c2pstr (macappname
);
3159 iErr
= FSMakeFSSpec (0, 0, macappname
, &spec
);
3167 lpbr
.launchBlockID
= extendedBlock
;
3168 lpbr
.launchEPBLength
= extendedBlockLen
;
3169 lpbr
.launchControlFlags
= launchContinue
+ launchNoFileFlags
;
3170 lpbr
.launchAppSpec
= &spec
;
3171 lpbr
.launchAppParameters
= NULL
;
3173 iErr
= LaunchApplication (&lpbr
); /* call the subprocess */
3180 send_event
.what
= kHighLevelEvent
;
3181 send_event
.message
= kEmacsSubprocessSend
;
3182 /* Event ID stored in "where" unused */
3185 /* OS may think current subprocess has terminated if previous one
3186 terminated recently. */
3189 iErr
= PostHighLevelEvent (&send_event
, &lpbr
.launchProcessSN
, 0, param
,
3190 paramlen
+ 1, receiverIDisPSN
);
3192 while (iErr
== sessClosedErr
&& retries
-- > 0);
3200 cursor_region_handle
= NewRgn ();
3202 /* Wait for the subprocess to finish, when it will send us a ERPY
3203 high level event. */
3205 if (WaitNextEvent (highLevelEventMask
, &reply_event
, 180,
3206 cursor_region_handle
)
3207 && reply_event
.message
== kEmacsSubprocessReply
)
3210 /* The return code is sent through the refCon */
3211 iErr
= AcceptHighLevelEvent (&targ
, &ref_con
, NULL
, &len
);
3214 DisposeHandle ((Handle
) cursor_region_handle
);
3219 DisposeHandle ((Handle
) cursor_region_handle
);
3223 #endif /* not TARGET_API_MAC_CARBON */
3228 opendir (const char *dirname
)
3230 char true_pathname
[MAXPATHLEN
+1], fully_resolved_name
[MAXPATHLEN
+1];
3231 char mac_pathname
[MAXPATHLEN
+1], vol_name
[MAXPATHLEN
+1];
3235 int len
, vol_name_len
;
3237 if (find_true_pathname (dirname
, true_pathname
, MAXPATHLEN
+1) == -1)
3240 len
= readlink (true_pathname
, fully_resolved_name
, MAXPATHLEN
);
3242 fully_resolved_name
[len
] = '\0';
3244 strcpy (fully_resolved_name
, true_pathname
);
3246 dirp
= (DIR *) malloc (sizeof(DIR));
3250 /* Handle special case when dirname is "/": sets up for readir to
3251 get all mount volumes. */
3252 if (strcmp (fully_resolved_name
, "/") == 0)
3254 dirp
->getting_volumes
= 1; /* special all mounted volumes DIR struct */
3255 dirp
->current_index
= 1; /* index for first volume */
3259 /* Handle typical cases: not accessing all mounted volumes. */
3260 if (!posix_to_mac_pathname (fully_resolved_name
, mac_pathname
, MAXPATHLEN
+1))
3263 /* Emacs calls opendir without the trailing '/', Mac needs trailing ':' */
3264 len
= strlen (mac_pathname
);
3265 if (mac_pathname
[len
- 1] != ':' && len
< MAXPATHLEN
)
3266 strcat (mac_pathname
, ":");
3268 /* Extract volume name */
3269 vol_name_len
= strchr (mac_pathname
, ':') - mac_pathname
;
3270 strncpy (vol_name
, mac_pathname
, vol_name_len
);
3271 vol_name
[vol_name_len
] = '\0';
3272 strcat (vol_name
, ":");
3274 c2pstr (mac_pathname
);
3275 cipb
.hFileInfo
.ioNamePtr
= mac_pathname
;
3276 /* using full pathname so vRefNum and DirID ignored */
3277 cipb
.hFileInfo
.ioVRefNum
= 0;
3278 cipb
.hFileInfo
.ioDirID
= 0;
3279 cipb
.hFileInfo
.ioFDirIndex
= 0;
3280 /* set to 0 to get information about specific dir or file */
3282 errno
= PBGetCatInfo (&cipb
, false);
3289 if (!(cipb
.hFileInfo
.ioFlAttrib
& 0x10)) /* bit 4 = 1 for directories */
3290 return 0; /* not a directory */
3292 dirp
->dir_id
= cipb
.dirInfo
.ioDrDirID
; /* used later in readdir */
3293 dirp
->getting_volumes
= 0;
3294 dirp
->current_index
= 1; /* index for first file/directory */
3297 vpb
.ioNamePtr
= vol_name
;
3298 /* using full pathname so vRefNum and DirID ignored */
3300 vpb
.ioVolIndex
= -1;
3301 errno
= PBHGetVInfo ((union HParamBlockRec
*) &vpb
, false);
3308 dirp
->vol_ref_num
= vpb
.ioVRefNum
;
3325 HParamBlockRec hpblock
;
3327 static struct dirent s_dirent
;
3328 static Str255 s_name
;
3332 /* Handle the root directory containing the mounted volumes. Call
3333 PBHGetVInfo specifying an index to obtain the info for a volume.
3334 PBHGetVInfo returns an error when it receives an index beyond the
3335 last volume, at which time we should return a nil dirent struct
3337 if (dp
->getting_volumes
)
3339 hpblock
.volumeParam
.ioNamePtr
= s_name
;
3340 hpblock
.volumeParam
.ioVRefNum
= 0;
3341 hpblock
.volumeParam
.ioVolIndex
= dp
->current_index
;
3343 errno
= PBHGetVInfo (&hpblock
, false);
3351 strcat (s_name
, "/"); /* need "/" for stat to work correctly */
3353 dp
->current_index
++;
3355 s_dirent
.d_ino
= hpblock
.volumeParam
.ioVRefNum
;
3356 s_dirent
.d_name
= s_name
;
3362 cipb
.hFileInfo
.ioVRefNum
= dp
->vol_ref_num
;
3363 cipb
.hFileInfo
.ioNamePtr
= s_name
;
3364 /* location to receive filename returned */
3366 /* return only visible files */
3370 cipb
.hFileInfo
.ioDirID
= dp
->dir_id
;
3371 /* directory ID found by opendir */
3372 cipb
.hFileInfo
.ioFDirIndex
= dp
->current_index
;
3374 errno
= PBGetCatInfo (&cipb
, false);
3381 /* insist on a visible entry */
3382 if (cipb
.hFileInfo
.ioFlAttrib
& 0x10) /* directory? */
3383 done
= !(cipb
.dirInfo
.ioDrUsrWds
.frFlags
& fInvisible
);
3385 done
= !(cipb
.hFileInfo
.ioFlFndrInfo
.fdFlags
& fInvisible
);
3387 dp
->current_index
++;
3400 s_dirent
.d_ino
= cipb
.dirInfo
.ioDrDirID
;
3401 /* value unimportant: non-zero for valid file */
3402 s_dirent
.d_name
= s_name
;
3412 char mac_pathname
[MAXPATHLEN
+1];
3413 Str255 directory_name
;
3417 if (path_from_vol_dir_name (mac_pathname
, 255, 0, 0, "\p") == 0)
3420 if (mac_to_posix_pathname (mac_pathname
, path
, MAXPATHLEN
+1) == 0)
3426 #endif /* ! MAC_OSX */
3430 initialize_applescript ()
3435 /* if open fails, as_scripting_component is set to NULL. Its
3436 subsequent use in OSA calls will fail with badComponentInstance
3438 as_scripting_component
= OpenDefaultComponent (kOSAComponentType
,
3439 kAppleScriptSubtype
);
3441 null_desc
.descriptorType
= typeNull
;
3442 null_desc
.dataHandle
= 0;
3443 osaerror
= OSAMakeContext (as_scripting_component
, &null_desc
,
3444 kOSANullScript
, &as_script_context
);
3446 as_script_context
= kOSANullScript
;
3447 /* use default context if create fails */
3452 terminate_applescript()
3454 OSADispose (as_scripting_component
, as_script_context
);
3455 CloseComponent (as_scripting_component
);
3458 /* Convert a lisp string to the 4 byte character code. */
3461 mac_get_code_from_arg(Lisp_Object arg
, OSType defCode
)
3470 /* check type string */
3472 if (SBYTES (arg
) != 4)
3474 error ("Wrong argument: need string of length 4 for code");
3476 result
= EndianU32_BtoN (*((UInt32
*) SDATA (arg
)));
3481 /* Convert the 4 byte character code into a 4 byte string. */
3484 mac_get_object_from_code(OSType defCode
)
3486 UInt32 code
= EndianU32_NtoB (defCode
);
3488 return make_unibyte_string ((char *)&code
, 4);
3492 DEFUN ("mac-get-file-creator", Fmac_get_file_creator
, Smac_get_file_creator
, 1, 1, 0,
3493 doc
: /* Get the creator code of FILENAME as a four character string. */)
3495 Lisp_Object filename
;
3504 Lisp_Object result
= Qnil
;
3505 CHECK_STRING (filename
);
3507 if (NILP(Ffile_exists_p(filename
)) || !NILP(Ffile_directory_p(filename
))) {
3510 filename
= Fexpand_file_name (filename
, Qnil
);
3514 status
= FSPathMakeRef(SDATA(ENCODE_FILE(filename
)), &fref
, NULL
);
3516 status
= posix_pathname_to_fsspec (SDATA (ENCODE_FILE (filename
)), &fss
);
3519 if (status
== noErr
)
3522 FSCatalogInfo catalogInfo
;
3524 status
= FSGetCatalogInfo(&fref
, kFSCatInfoFinderInfo
,
3525 &catalogInfo
, NULL
, NULL
, NULL
);
3529 status
= FSpGetFInfo (&fss
, &finder_info
);
3531 if (status
== noErr
)
3534 result
= mac_get_object_from_code(((FileInfo
*)&catalogInfo
.finderInfo
)->fileCreator
);
3536 result
= mac_get_object_from_code (finder_info
.fdCreator
);
3541 if (status
!= noErr
) {
3542 error ("Error while getting file information.");
3547 DEFUN ("mac-get-file-type", Fmac_get_file_type
, Smac_get_file_type
, 1, 1, 0,
3548 doc
: /* Get the type code of FILENAME as a four character string. */)
3550 Lisp_Object filename
;
3559 Lisp_Object result
= Qnil
;
3560 CHECK_STRING (filename
);
3562 if (NILP(Ffile_exists_p(filename
)) || !NILP(Ffile_directory_p(filename
))) {
3565 filename
= Fexpand_file_name (filename
, Qnil
);
3569 status
= FSPathMakeRef(SDATA(ENCODE_FILE(filename
)), &fref
, NULL
);
3571 status
= posix_pathname_to_fsspec (SDATA (ENCODE_FILE (filename
)), &fss
);
3574 if (status
== noErr
)
3577 FSCatalogInfo catalogInfo
;
3579 status
= FSGetCatalogInfo(&fref
, kFSCatInfoFinderInfo
,
3580 &catalogInfo
, NULL
, NULL
, NULL
);
3584 status
= FSpGetFInfo (&fss
, &finder_info
);
3586 if (status
== noErr
)
3589 result
= mac_get_object_from_code(((FileInfo
*)&catalogInfo
.finderInfo
)->fileType
);
3591 result
= mac_get_object_from_code (finder_info
.fdType
);
3596 if (status
!= noErr
) {
3597 error ("Error while getting file information.");
3602 DEFUN ("mac-set-file-creator", Fmac_set_file_creator
, Smac_set_file_creator
, 1, 2, 0,
3603 doc
: /* Set creator code of file FILENAME to CODE.
3604 If non-nil, CODE must be a 4-character string. Otherwise, 'EMAx' is
3605 assumed. Return non-nil if successful. */)
3607 Lisp_Object filename
, code
;
3616 CHECK_STRING (filename
);
3618 cCode
= mac_get_code_from_arg(code
, 'EMAx');
3620 if (NILP(Ffile_exists_p(filename
)) || !NILP(Ffile_directory_p(filename
))) {
3623 filename
= Fexpand_file_name (filename
, Qnil
);
3627 status
= FSPathMakeRef(SDATA(ENCODE_FILE(filename
)), &fref
, NULL
);
3629 status
= posix_pathname_to_fsspec (SDATA (ENCODE_FILE (filename
)), &fss
);
3632 if (status
== noErr
)
3635 FSCatalogInfo catalogInfo
;
3637 status
= FSGetCatalogInfo(&fref
, kFSCatInfoFinderInfo
,
3638 &catalogInfo
, NULL
, NULL
, &parentDir
);
3642 status
= FSpGetFInfo (&fss
, &finder_info
);
3644 if (status
== noErr
)
3647 ((FileInfo
*)&catalogInfo
.finderInfo
)->fileCreator
= cCode
;
3648 status
= FSSetCatalogInfo(&fref
, kFSCatInfoFinderInfo
, &catalogInfo
);
3649 /* TODO: on Mac OS 10.2, we need to touch the parent dir, FNNotify? */
3651 finder_info
.fdCreator
= cCode
;
3652 status
= FSpSetFInfo (&fss
, &finder_info
);
3657 if (status
!= noErr
) {
3658 error ("Error while setting creator information.");
3663 DEFUN ("mac-set-file-type", Fmac_set_file_type
, Smac_set_file_type
, 2, 2, 0,
3664 doc
: /* Set file code of file FILENAME to CODE.
3665 CODE must be a 4-character string. Return non-nil if successful. */)
3667 Lisp_Object filename
, code
;
3676 CHECK_STRING (filename
);
3678 cCode
= mac_get_code_from_arg(code
, 0); /* Default to empty code*/
3680 if (NILP(Ffile_exists_p(filename
)) || !NILP(Ffile_directory_p(filename
))) {
3683 filename
= Fexpand_file_name (filename
, Qnil
);
3687 status
= FSPathMakeRef(SDATA(ENCODE_FILE(filename
)), &fref
, NULL
);
3689 status
= posix_pathname_to_fsspec (SDATA (ENCODE_FILE (filename
)), &fss
);
3692 if (status
== noErr
)
3695 FSCatalogInfo catalogInfo
;
3697 status
= FSGetCatalogInfo(&fref
, kFSCatInfoFinderInfo
,
3698 &catalogInfo
, NULL
, NULL
, &parentDir
);
3702 status
= FSpGetFInfo (&fss
, &finder_info
);
3704 if (status
== noErr
)
3707 ((FileInfo
*)&catalogInfo
.finderInfo
)->fileType
= cCode
;
3708 status
= FSSetCatalogInfo(&fref
, kFSCatInfoFinderInfo
, &catalogInfo
);
3709 /* TODO: on Mac OS 10.2, we need to touch the parent dir, FNNotify? */
3711 finder_info
.fdType
= cCode
;
3712 status
= FSpSetFInfo (&fss
, &finder_info
);
3717 if (status
!= noErr
) {
3718 error ("Error while setting creator information.");
3724 /* Compile and execute the AppleScript SCRIPT and return the error
3725 status as function value. A zero is returned if compilation and
3726 execution is successful, in which case RESULT returns a pointer to
3727 a string containing the resulting script value. Otherwise, the Mac
3728 error code is returned and RESULT returns a pointer to an error
3729 string. In both cases the caller should deallocate the storage
3730 used by the string pointed to by RESULT if it is non-NULL. For
3731 documentation on the MacOS scripting architecture, see Inside
3732 Macintosh - Interapplication Communications: Scripting Components. */
3735 do_applescript (char *script
, char **result
)
3737 AEDesc script_desc
, result_desc
, error_desc
;
3744 if (!as_scripting_component
)
3745 initialize_applescript();
3747 error
= AECreateDesc (typeChar
, script
, strlen(script
), &script_desc
);
3751 osaerror
= OSADoScript (as_scripting_component
, &script_desc
, kOSANullScript
,
3752 typeChar
, kOSAModeNull
, &result_desc
);
3754 if (osaerror
== errOSAScriptError
)
3756 /* error executing AppleScript: retrieve error message */
3757 if (!OSAScriptError (as_scripting_component
, kOSAErrorMessage
, typeChar
,
3760 #if TARGET_API_MAC_CARBON
3761 length
= AEGetDescDataSize (&error_desc
);
3762 *result
= (char *) xmalloc (length
+ 1);
3765 AEGetDescData (&error_desc
, *result
, length
);
3766 *(*result
+ length
) = '\0';
3768 #else /* not TARGET_API_MAC_CARBON */
3769 HLock (error_desc
.dataHandle
);
3770 length
= GetHandleSize(error_desc
.dataHandle
);
3771 *result
= (char *) xmalloc (length
+ 1);
3774 memcpy (*result
, *(error_desc
.dataHandle
), length
);
3775 *(*result
+ length
) = '\0';
3777 HUnlock (error_desc
.dataHandle
);
3778 #endif /* not TARGET_API_MAC_CARBON */
3779 AEDisposeDesc (&error_desc
);
3782 else if (osaerror
== noErr
) /* success: retrieve resulting script value */
3784 #if TARGET_API_MAC_CARBON
3785 length
= AEGetDescDataSize (&result_desc
);
3786 *result
= (char *) xmalloc (length
+ 1);
3789 AEGetDescData (&result_desc
, *result
, length
);
3790 *(*result
+ length
) = '\0';
3792 #else /* not TARGET_API_MAC_CARBON */
3793 HLock (result_desc
.dataHandle
);
3794 length
= GetHandleSize(result_desc
.dataHandle
);
3795 *result
= (char *) xmalloc (length
+ 1);
3798 memcpy (*result
, *(result_desc
.dataHandle
), length
);
3799 *(*result
+ length
) = '\0';
3801 HUnlock (result_desc
.dataHandle
);
3802 #endif /* not TARGET_API_MAC_CARBON */
3803 AEDisposeDesc (&result_desc
);
3806 AEDisposeDesc (&script_desc
);
3812 DEFUN ("do-applescript", Fdo_applescript
, Sdo_applescript
, 1, 1, 0,
3813 doc
: /* Compile and execute AppleScript SCRIPT and return the result.
3814 If compilation and execution are successful, the resulting script
3815 value is returned as a string. Otherwise the function aborts and
3816 displays the error message returned by the AppleScript scripting
3821 char *result
, *temp
;
3822 Lisp_Object lisp_result
;
3825 CHECK_STRING (script
);
3828 status
= do_applescript (SDATA (script
), &result
);
3833 error ("AppleScript error %d", status
);
3836 /* Unfortunately only OSADoScript in do_applescript knows how
3837 how large the resulting script value or error message is
3838 going to be and therefore as caller memory must be
3839 deallocated here. It is necessary to free the error
3840 message before calling error to avoid a memory leak. */
3841 temp
= (char *) alloca (strlen (result
) + 1);
3842 strcpy (temp
, result
);
3849 lisp_result
= build_string (result
);
3856 DEFUN ("mac-file-name-to-posix", Fmac_file_name_to_posix
,
3857 Smac_file_name_to_posix
, 1, 1, 0,
3858 doc
: /* Convert Macintosh FILENAME to Posix form. */)
3860 Lisp_Object filename
;
3862 char posix_filename
[MAXPATHLEN
+1];
3864 CHECK_STRING (filename
);
3866 if (mac_to_posix_pathname (SDATA (filename
), posix_filename
, MAXPATHLEN
))
3867 return build_string (posix_filename
);
3873 DEFUN ("posix-file-name-to-mac", Fposix_file_name_to_mac
,
3874 Sposix_file_name_to_mac
, 1, 1, 0,
3875 doc
: /* Convert Posix FILENAME to Mac form. */)
3877 Lisp_Object filename
;
3879 char mac_filename
[MAXPATHLEN
+1];
3881 CHECK_STRING (filename
);
3883 if (posix_to_mac_pathname (SDATA (filename
), mac_filename
, MAXPATHLEN
))
3884 return build_string (mac_filename
);
3890 #if TARGET_API_MAC_CARBON
3891 static Lisp_Object Qxml
, Qmime_charset
;
3892 static Lisp_Object QNFD
, QNFKD
, QNFC
, QNFKC
, QHFS_plus_D
, QHFS_plus_C
;
3894 DEFUN ("mac-get-preference", Fmac_get_preference
, Smac_get_preference
, 1, 4, 0,
3895 doc
: /* Return the application preference value for KEY.
3896 KEY is either a string specifying a preference key, or a list of key
3897 strings. If it is a list, the (i+1)-th element is used as a key for
3898 the CFDictionary value obtained by the i-th element. Return nil if
3899 lookup is failed at some stage.
3901 Optional arg APPLICATION is an application ID string. If omitted or
3902 nil, that stands for the current application.
3904 Optional arg FORMAT specifies the data format of the return value. If
3905 omitted or nil, each Core Foundation object is converted into a
3906 corresponding Lisp object as follows:
3908 Core Foundation Lisp Tag
3909 ------------------------------------------------------------
3910 CFString Multibyte string string
3911 CFNumber Integer or float number
3912 CFBoolean Symbol (t or nil) boolean
3913 CFDate List of three integers date
3914 (cf. `current-time')
3915 CFData Unibyte string data
3916 CFArray Vector array
3917 CFDictionary Alist or hash table dictionary
3918 (depending on HASH-BOUND)
3920 If it is t, a symbol that represents the type of the original Core
3921 Foundation object is prepended. If it is `xml', the value is returned
3922 as an XML representation.
3924 Optional arg HASH-BOUND specifies which kinds of the list objects,
3925 alists or hash tables, are used as the targets of the conversion from
3926 CFDictionary. If HASH-BOUND is a negative integer or nil, always
3927 generate alists. If HASH-BOUND >= 0, generate an alist if the number
3928 of keys in the dictionary is smaller than HASH-BOUND, and a hash table
3930 (key
, application
, format
, hash_bound
)
3931 Lisp_Object key
, application
, format
, hash_bound
;
3933 CFStringRef app_id
, key_str
;
3934 CFPropertyListRef app_plist
= NULL
, plist
;
3935 Lisp_Object result
= Qnil
, tmp
;
3938 key
= Fcons (key
, Qnil
);
3942 for (tmp
= key
; CONSP (tmp
); tmp
= XCDR (tmp
))
3943 CHECK_STRING_CAR (tmp
);
3945 wrong_type_argument (Qlistp
, key
);
3947 if (!NILP (application
))
3948 CHECK_STRING (application
);
3949 CHECK_SYMBOL (format
);
3950 if (!NILP (hash_bound
))
3951 CHECK_NUMBER (hash_bound
);
3955 app_id
= kCFPreferencesCurrentApplication
;
3956 if (!NILP (application
))
3958 app_id
= cfstring_create_with_string (application
);
3962 key_str
= cfstring_create_with_string (XCAR (key
));
3963 if (key_str
== NULL
)
3965 app_plist
= CFPreferencesCopyAppValue (key_str
, app_id
);
3966 CFRelease (key_str
);
3967 if (app_plist
== NULL
)
3971 for (key
= XCDR (key
); CONSP (key
); key
= XCDR (key
))
3973 if (CFGetTypeID (plist
) != CFDictionaryGetTypeID ())
3975 key_str
= cfstring_create_with_string (XCAR (key
));
3976 if (key_str
== NULL
)
3978 plist
= CFDictionaryGetValue (plist
, key_str
);
3979 CFRelease (key_str
);
3985 if (EQ (format
, Qxml
))
3987 CFDataRef data
= CFPropertyListCreateXMLData (NULL
, plist
);
3990 result
= cfdata_to_lisp (data
);
3995 cfproperty_list_to_lisp (plist
, EQ (format
, Qt
),
3996 NILP (hash_bound
) ? -1 : XINT (hash_bound
));
4000 CFRelease (app_plist
);
4009 static CFStringEncoding
4010 get_cfstring_encoding_from_lisp (obj
)
4013 CFStringRef iana_name
;
4014 CFStringEncoding encoding
= kCFStringEncodingInvalidId
;
4017 return kCFStringEncodingUnicode
;
4022 if (SYMBOLP (obj
) && !NILP (Fcoding_system_p (obj
)))
4024 Lisp_Object coding_spec
, plist
;
4026 coding_spec
= Fget (obj
, Qcoding_system
);
4027 plist
= XVECTOR (coding_spec
)->contents
[3];
4028 obj
= Fplist_get (XVECTOR (coding_spec
)->contents
[3], Qmime_charset
);
4032 obj
= SYMBOL_NAME (obj
);
4036 iana_name
= cfstring_create_with_string (obj
);
4039 encoding
= CFStringConvertIANACharSetNameToEncoding (iana_name
);
4040 CFRelease (iana_name
);
4047 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
4049 cfstring_create_normalized (str
, symbol
)
4054 TextEncodingVariant variant
;
4055 float initial_mag
= 0.0;
4056 CFStringRef result
= NULL
;
4058 if (EQ (symbol
, QNFD
))
4059 form
= kCFStringNormalizationFormD
;
4060 else if (EQ (symbol
, QNFKD
))
4061 form
= kCFStringNormalizationFormKD
;
4062 else if (EQ (symbol
, QNFC
))
4063 form
= kCFStringNormalizationFormC
;
4064 else if (EQ (symbol
, QNFKC
))
4065 form
= kCFStringNormalizationFormKC
;
4066 else if (EQ (symbol
, QHFS_plus_D
))
4068 variant
= kUnicodeHFSPlusDecompVariant
;
4071 else if (EQ (symbol
, QHFS_plus_C
))
4073 variant
= kUnicodeHFSPlusCompVariant
;
4079 CFMutableStringRef mut_str
= CFStringCreateMutableCopy (NULL
, 0, str
);
4083 CFStringNormalize (mut_str
, form
);
4087 else if (initial_mag
> 0.0)
4089 UnicodeToTextInfo uni
= NULL
;
4092 UniChar
*in_text
, *buffer
= NULL
, *out_buf
= NULL
;
4094 ByteCount out_read
, out_size
, out_len
;
4096 map
.unicodeEncoding
= CreateTextEncoding (kTextEncodingUnicodeDefault
,
4098 kTextEncodingDefaultFormat
);
4099 map
.otherEncoding
= CreateTextEncoding (kTextEncodingUnicodeDefault
,
4101 kTextEncodingDefaultFormat
);
4102 map
.mappingVersion
= kUnicodeUseLatestMapping
;
4104 length
= CFStringGetLength (str
);
4105 out_size
= (int)((float)length
* initial_mag
) * sizeof (UniChar
);
4109 in_text
= (UniChar
*)CFStringGetCharactersPtr (str
);
4110 if (in_text
== NULL
)
4112 buffer
= xmalloc (sizeof (UniChar
) * length
);
4115 CFStringGetCharacters (str
, CFRangeMake (0, length
), buffer
);
4121 err
= CreateUnicodeToTextInfo(&map
, &uni
);
4122 while (err
== noErr
)
4124 out_buf
= xmalloc (out_size
);
4125 if (out_buf
== NULL
)
4128 err
= ConvertFromUnicodeToText (uni
, length
* sizeof (UniChar
),
4130 kUnicodeDefaultDirectionMask
,
4131 0, NULL
, NULL
, NULL
,
4132 out_size
, &out_read
, &out_len
,
4134 if (err
== noErr
&& out_read
< length
* sizeof (UniChar
))
4143 result
= CFStringCreateWithCharacters (NULL
, out_buf
,
4144 out_len
/ sizeof (UniChar
));
4146 DisposeUnicodeToTextInfo (&uni
);
4162 DEFUN ("mac-code-convert-string", Fmac_code_convert_string
, Smac_code_convert_string
, 3, 4, 0,
4163 doc
: /* Convert STRING from SOURCE encoding to TARGET encoding.
4164 The conversion is performed using the converter provided by the system.
4165 Each encoding is specified by either a coding system symbol, a mime
4166 charset string, or an integer as a CFStringEncoding value. Nil for
4167 encoding means UTF-16 in native byte order, no byte order mark.
4168 On Mac OS X 10.2 and later, you can do Unicode Normalization by
4169 specifying the optional argument NORMALIZATION-FORM with a symbol NFD,
4170 NFKD, NFC, NFKC, HFS+D, or HFS+C.
4171 On successful conversion, return the result string, else return nil. */)
4172 (string
, source
, target
, normalization_form
)
4173 Lisp_Object string
, source
, target
, normalization_form
;
4175 Lisp_Object result
= Qnil
;
4176 CFStringEncoding src_encoding
, tgt_encoding
;
4177 CFStringRef str
= NULL
;
4179 CHECK_STRING (string
);
4180 if (!INTEGERP (source
) && !STRINGP (source
))
4181 CHECK_SYMBOL (source
);
4182 if (!INTEGERP (target
) && !STRINGP (target
))
4183 CHECK_SYMBOL (target
);
4184 CHECK_SYMBOL (normalization_form
);
4188 src_encoding
= get_cfstring_encoding_from_lisp (source
);
4189 tgt_encoding
= get_cfstring_encoding_from_lisp (target
);
4191 /* We really want string_to_unibyte, but since it doesn't exist yet, we
4192 use string_as_unibyte which works as well, except for the fact that
4193 it's too permissive (it doesn't check that the multibyte string only
4194 contain single-byte chars). */
4195 string
= Fstring_as_unibyte (string
);
4196 if (src_encoding
!= kCFStringEncodingInvalidId
4197 && tgt_encoding
!= kCFStringEncodingInvalidId
)
4198 str
= CFStringCreateWithBytes (NULL
, SDATA (string
), SBYTES (string
),
4199 src_encoding
, !NILP (source
));
4200 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
4203 CFStringRef saved_str
= str
;
4205 str
= cfstring_create_normalized (saved_str
, normalization_form
);
4206 CFRelease (saved_str
);
4211 CFIndex str_len
, buf_len
;
4213 str_len
= CFStringGetLength (str
);
4214 if (CFStringGetBytes (str
, CFRangeMake (0, str_len
), tgt_encoding
, 0,
4215 !NILP (target
), NULL
, 0, &buf_len
) == str_len
)
4217 result
= make_uninit_string (buf_len
);
4218 CFStringGetBytes (str
, CFRangeMake (0, str_len
), tgt_encoding
, 0,
4219 !NILP (target
), SDATA (result
), buf_len
, NULL
);
4228 #endif /* TARGET_API_MAC_CARBON */
4231 DEFUN ("mac-clear-font-name-table", Fmac_clear_font_name_table
, Smac_clear_font_name_table
, 0, 0, 0,
4232 doc
: /* Clear the font name table. */)
4236 mac_clear_font_name_table ();
4242 mac_get_system_locale ()
4250 lang
= GetScriptVariable (smSystemScript
, smScriptLang
);
4251 region
= GetScriptManagerVariable (smRegionCode
);
4252 err
= LocaleRefFromLangOrRegionCode (lang
, region
, &locale
);
4254 err
= LocaleRefGetPartString (locale
, kLocaleAllPartsMask
,
4257 return build_string (str
);
4266 extern int inhibit_window_system
;
4267 extern int noninteractive
;
4269 /* Unlike in X11, window events in Carbon do not come from sockets.
4270 So we cannot simply use `select' to monitor two kinds of inputs:
4271 window events and process outputs. We emulate such functionality
4272 by regarding fd 0 as the window event channel and simultaneously
4273 monitoring both kinds of input channels. It is implemented by
4274 dividing into some cases:
4275 1. The window event channel is not involved.
4277 2. Sockets are not involved.
4278 -> Use ReceiveNextEvent.
4279 3. [If SELECT_USE_CFSOCKET is defined]
4280 Only the window event channel and socket read channels are
4281 involved, and timeout is not too short (greater than
4282 SELECT_TIMEOUT_THRESHHOLD_RUNLOOP seconds).
4283 -> Create CFSocket for each socket and add it into the current
4284 event RunLoop so that a `ready-to-read' event can be posted
4285 to the event queue that is also used for window events. Then
4286 ReceiveNextEvent can wait for both kinds of inputs.
4288 -> Periodically poll the window input channel while repeatedly
4289 executing `select' with a short timeout
4290 (SELECT_POLLING_PERIOD_USEC microseconds). */
4292 #define SELECT_POLLING_PERIOD_USEC 20000
4293 #ifdef SELECT_USE_CFSOCKET
4294 #define SELECT_TIMEOUT_THRESHOLD_RUNLOOP 0.2
4295 #define EVENT_CLASS_SOCK 'Sock'
4298 socket_callback (s
, type
, address
, data
, info
)
4300 CFSocketCallBackType type
;
4307 CreateEvent (NULL
, EVENT_CLASS_SOCK
, 0, 0, kEventAttributeNone
, &event
);
4308 PostEventToQueue (GetCurrentEventQueue (), event
, kEventPriorityStandard
);
4309 ReleaseEvent (event
);
4311 #endif /* SELECT_USE_CFSOCKET */
4314 select_and_poll_event (n
, rfds
, wfds
, efds
, timeout
)
4319 struct timeval
*timeout
;
4324 r
= select (n
, rfds
, wfds
, efds
, timeout
);
4328 err
= ReceiveNextEvent (0, NULL
, kEventDurationNoWait
,
4329 kEventLeaveInQueue
, NULL
);
4340 #if MAC_OS_X_VERSION_MAX_ALLOWED < 1020
4341 #undef SELECT_INVALIDATE_CFSOCKET
4345 sys_select (n
, rfds
, wfds
, efds
, timeout
)
4350 struct timeval
*timeout
;
4354 EMACS_TIME select_timeout
;
4356 if (inhibit_window_system
|| noninteractive
4357 || rfds
== NULL
|| !FD_ISSET (0, rfds
))
4358 return select (n
, rfds
, wfds
, efds
, timeout
);
4362 if (wfds
== NULL
&& efds
== NULL
)
4365 SELECT_TYPE orfds
= *rfds
;
4367 EventTimeout timeout_sec
=
4369 ? (EMACS_SECS (*timeout
) * kEventDurationSecond
4370 + EMACS_USECS (*timeout
) * kEventDurationMicrosecond
)
4371 : kEventDurationForever
);
4373 for (i
= 1; i
< n
; i
++)
4374 if (FD_ISSET (i
, rfds
))
4380 err
= ReceiveNextEvent (0, NULL
, timeout_sec
,
4381 kEventLeaveInQueue
, NULL
);
4392 /* Avoid initial overhead of RunLoop setup for the case that
4393 some input is already available. */
4394 EMACS_SET_SECS_USECS (select_timeout
, 0, 0);
4395 r
= select_and_poll_event (n
, rfds
, wfds
, efds
, &select_timeout
);
4396 if (r
!= 0 || timeout_sec
== 0.0)
4401 #ifdef SELECT_USE_CFSOCKET
4402 if (timeout_sec
> 0 && timeout_sec
<= SELECT_TIMEOUT_THRESHOLD_RUNLOOP
)
4403 goto poll_periodically
;
4406 CFRunLoopRef runloop
=
4407 (CFRunLoopRef
) GetCFRunLoopFromEventLoop (GetCurrentEventLoop ());
4408 EventTypeSpec specs
[] = {{EVENT_CLASS_SOCK
, 0}};
4409 #ifdef SELECT_INVALIDATE_CFSOCKET
4410 CFSocketRef
*shead
, *s
;
4412 CFRunLoopSourceRef
*shead
, *s
;
4417 #ifdef SELECT_INVALIDATE_CFSOCKET
4418 shead
= xmalloc (sizeof (CFSocketRef
) * nsocks
);
4420 shead
= xmalloc (sizeof (CFRunLoopSourceRef
) * nsocks
);
4423 for (i
= 1; i
< n
; i
++)
4424 if (FD_ISSET (i
, rfds
))
4426 CFSocketRef socket
=
4427 CFSocketCreateWithNative (NULL
, i
, kCFSocketReadCallBack
,
4428 socket_callback
, NULL
);
4429 CFRunLoopSourceRef source
=
4430 CFSocketCreateRunLoopSource (NULL
, socket
, 0);
4432 #ifdef SELECT_INVALIDATE_CFSOCKET
4433 CFSocketSetSocketFlags (socket
, 0);
4435 CFRunLoopAddSource (runloop
, source
, kCFRunLoopDefaultMode
);
4436 #ifdef SELECT_INVALIDATE_CFSOCKET
4446 err
= ReceiveNextEvent (0, NULL
, timeout_sec
, kEventLeaveInQueue
, NULL
);
4451 #ifdef SELECT_INVALIDATE_CFSOCKET
4452 CFSocketInvalidate (*s
);
4454 CFRunLoopRemoveSource (runloop
, *s
, kCFRunLoopDefaultMode
);
4469 FlushEventsMatchingListFromQueue (GetCurrentEventQueue (),
4470 GetEventTypeCount (specs
),
4472 EMACS_SET_SECS_USECS (select_timeout
, 0, 0);
4473 r
= select_and_poll_event (n
, rfds
, wfds
, efds
, &select_timeout
);
4480 #endif /* SELECT_USE_CFSOCKET */
4485 EMACS_TIME end_time
, now
, remaining_time
;
4486 SELECT_TYPE orfds
= *rfds
, owfds
, oefds
;
4494 remaining_time
= *timeout
;
4495 EMACS_GET_TIME (now
);
4496 EMACS_ADD_TIME (end_time
, now
, remaining_time
);
4501 EMACS_SET_SECS_USECS (select_timeout
, 0, SELECT_POLLING_PERIOD_USEC
);
4502 if (timeout
&& EMACS_TIME_LT (remaining_time
, select_timeout
))
4503 select_timeout
= remaining_time
;
4504 r
= select_and_poll_event (n
, rfds
, wfds
, efds
, &select_timeout
);
4516 EMACS_GET_TIME (now
);
4517 EMACS_SUB_TIME (remaining_time
, end_time
, now
);
4520 while (!timeout
|| EMACS_TIME_LT (now
, end_time
));
4531 /* Set up environment variables so that Emacs can correctly find its
4532 support files when packaged as an application bundle. Directories
4533 placed in /usr/local/share/emacs/<emacs-version>/, /usr/local/bin,
4534 and /usr/local/libexec/emacs/<emacs-version>/<system-configuration>
4535 by `make install' by default can instead be placed in
4536 .../Emacs.app/Contents/Resources/ and
4537 .../Emacs.app/Contents/MacOS/. Each of these environment variables
4538 is changed only if it is not already set. Presumably if the user
4539 sets an environment variable, he will want to use files in his path
4540 instead of ones in the application bundle. */
4542 init_mac_osx_environment ()
4546 CFStringRef cf_app_bundle_pathname
;
4547 int app_bundle_pathname_len
;
4548 char *app_bundle_pathname
;
4552 /* Initialize locale related variables. */
4553 mac_system_script_code
=
4554 (ScriptCode
) GetScriptManagerVariable (smSysScript
);
4555 Vmac_system_locale
= mac_get_system_locale ();
4557 /* Fetch the pathname of the application bundle as a C string into
4558 app_bundle_pathname. */
4560 bundle
= CFBundleGetMainBundle ();
4561 if (!bundle
|| CFBundleGetIdentifier (bundle
) == NULL
)
4563 /* We could not find the bundle identifier. For now, prevent
4564 the fatal error by bringing it up in the terminal. */
4565 inhibit_window_system
= 1;
4569 bundleURL
= CFBundleCopyBundleURL (bundle
);
4573 cf_app_bundle_pathname
= CFURLCopyFileSystemPath (bundleURL
,
4574 kCFURLPOSIXPathStyle
);
4575 app_bundle_pathname_len
= CFStringGetLength (cf_app_bundle_pathname
);
4576 app_bundle_pathname
= (char *) alloca (app_bundle_pathname_len
+ 1);
4578 if (!CFStringGetCString (cf_app_bundle_pathname
,
4579 app_bundle_pathname
,
4580 app_bundle_pathname_len
+ 1,
4581 kCFStringEncodingISOLatin1
))
4583 CFRelease (cf_app_bundle_pathname
);
4587 CFRelease (cf_app_bundle_pathname
);
4589 /* P should have sufficient room for the pathname of the bundle plus
4590 the subpath in it leading to the respective directories. Q
4591 should have three times that much room because EMACSLOADPATH can
4592 have the value "<path to lisp dir>:<path to leim dir>:<path to
4594 p
= (char *) alloca (app_bundle_pathname_len
+ 50);
4595 q
= (char *) alloca (3 * app_bundle_pathname_len
+ 150);
4596 if (!getenv ("EMACSLOADPATH"))
4600 strcpy (p
, app_bundle_pathname
);
4601 strcat (p
, "/Contents/Resources/lisp");
4602 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
4605 strcpy (p
, app_bundle_pathname
);
4606 strcat (p
, "/Contents/Resources/leim");
4607 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
4614 strcpy (p
, app_bundle_pathname
);
4615 strcat (p
, "/Contents/Resources/site-lisp");
4616 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
4624 setenv ("EMACSLOADPATH", q
, 1);
4627 if (!getenv ("EMACSPATH"))
4631 strcpy (p
, app_bundle_pathname
);
4632 strcat (p
, "/Contents/MacOS/libexec");
4633 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
4636 strcpy (p
, app_bundle_pathname
);
4637 strcat (p
, "/Contents/MacOS/bin");
4638 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
4646 setenv ("EMACSPATH", q
, 1);
4649 if (!getenv ("EMACSDATA"))
4651 strcpy (p
, app_bundle_pathname
);
4652 strcat (p
, "/Contents/Resources/etc");
4653 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
4654 setenv ("EMACSDATA", p
, 1);
4657 if (!getenv ("EMACSDOC"))
4659 strcpy (p
, app_bundle_pathname
);
4660 strcat (p
, "/Contents/Resources/etc");
4661 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
4662 setenv ("EMACSDOC", p
, 1);
4665 if (!getenv ("INFOPATH"))
4667 strcpy (p
, app_bundle_pathname
);
4668 strcat (p
, "/Contents/Resources/info");
4669 if (stat (p
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == S_IFDIR
)
4670 setenv ("INFOPATH", p
, 1);
4673 #endif /* MAC_OSX */
4679 #if TARGET_API_MAC_CARBON
4680 Qstring
= intern ("string"); staticpro (&Qstring
);
4681 Qnumber
= intern ("number"); staticpro (&Qnumber
);
4682 Qboolean
= intern ("boolean"); staticpro (&Qboolean
);
4683 Qdate
= intern ("date"); staticpro (&Qdate
);
4684 Qdata
= intern ("data"); staticpro (&Qdata
);
4685 Qarray
= intern ("array"); staticpro (&Qarray
);
4686 Qdictionary
= intern ("dictionary"); staticpro (&Qdictionary
);
4688 Qxml
= intern ("xml");
4691 Qmime_charset
= intern ("mime-charset");
4692 staticpro (&Qmime_charset
);
4694 QNFD
= intern ("NFD"); staticpro (&QNFD
);
4695 QNFKD
= intern ("NFKD"); staticpro (&QNFKD
);
4696 QNFC
= intern ("NFC"); staticpro (&QNFC
);
4697 QNFKC
= intern ("NFKC"); staticpro (&QNFKC
);
4698 QHFS_plus_D
= intern ("HFS+D"); staticpro (&QHFS_plus_D
);
4699 QHFS_plus_C
= intern ("HFS+C"); staticpro (&QHFS_plus_C
);
4702 #if TARGET_API_MAC_CARBON
4703 defsubr (&Smac_get_preference
);
4704 defsubr (&Smac_code_convert_string
);
4706 defsubr (&Smac_clear_font_name_table
);
4708 defsubr (&Smac_set_file_creator
);
4709 defsubr (&Smac_set_file_type
);
4710 defsubr (&Smac_get_file_creator
);
4711 defsubr (&Smac_get_file_type
);
4712 defsubr (&Sdo_applescript
);
4713 defsubr (&Smac_file_name_to_posix
);
4714 defsubr (&Sposix_file_name_to_mac
);
4716 DEFVAR_INT ("mac-system-script-code", &mac_system_script_code
,
4717 doc
: /* The system script code. */);
4718 mac_system_script_code
= (ScriptCode
) GetScriptManagerVariable (smSysScript
);
4720 DEFVAR_LISP ("mac-system-locale", &Vmac_system_locale
,
4721 doc
: /* The system locale identifier string.
4722 This is not a POSIX locale ID, but an ICU locale ID. So encoding
4723 information is not included. */);
4724 Vmac_system_locale
= mac_get_system_locale ();
4727 /* arch-tag: 29d30c1f-0c6b-4f88-8a6d-0558d7f9dbff
4728 (do not change this comment) */