Mercurial > emacs
comparison src/mac.c @ 90127:30ad2795fdab
Revision: miles@gnu.org--gnu-2005/emacs--unicode--0--patch-28
Merge from emacs--cvs-trunk--0
Patches applied:
* emacs--cvs-trunk--0 (patch 180-191)
- Update from CVS
- Merge from gnus--rel--5.10
* gnus--rel--5.10 (patch 39-44)
- Merge from emacs--cvs-trunk--0
- Update from CVS
author | Miles Bader <miles@gnu.org> |
---|---|
date | Sat, 19 Mar 2005 02:42:17 +0000 |
parents | 29e773288013 40fe172d199c |
children | 02f1dbc4a199 |
comparison
equal
deleted
inserted
replaced
90126:8ee106ee2dc8 | 90127:30ad2795fdab |
---|---|
24 | 24 |
25 #include <stdio.h> | 25 #include <stdio.h> |
26 #include <errno.h> | 26 #include <errno.h> |
27 #include <time.h> | 27 #include <time.h> |
28 | 28 |
29 #ifdef HAVE_CARBON | 29 #include "lisp.h" |
30 #ifdef MAC_OSX | 30 #include "process.h" |
31 #undef mktime | 31 #include "sysselect.h" |
32 #undef DEBUG | 32 #include "systime.h" |
33 #undef free | 33 #include "blockinput.h" |
34 #undef malloc | 34 |
35 #undef realloc | 35 #include "macterm.h" |
36 #undef init_process | 36 |
37 #include <Carbon/Carbon.h> | 37 #ifndef HAVE_CARBON |
38 #undef mktime | |
39 #define mktime emacs_mktime | |
40 #undef free | |
41 #define free unexec_free | |
42 #undef malloc | |
43 #define malloc unexec_malloc | |
44 #undef realloc | |
45 #define realloc unexec_realloc | |
46 #undef init_process | |
47 #define init_process emacs_init_process | |
48 #else /* not MAC_OSX */ | |
49 #undef SIGHUP | |
50 #define OLDP2C 1 | |
51 #include <Carbon.h> | |
52 #endif /* not MAC_OSX */ | |
53 #else /* not HAVE_CARBON */ | |
54 #include <Files.h> | 38 #include <Files.h> |
55 #include <MacTypes.h> | 39 #include <MacTypes.h> |
56 #include <TextUtils.h> | 40 #include <TextUtils.h> |
57 #include <Folders.h> | 41 #include <Folders.h> |
58 #include <Resources.h> | 42 #include <Resources.h> |
78 #include <stdlib.h> | 62 #include <stdlib.h> |
79 #include <fcntl.h> | 63 #include <fcntl.h> |
80 #if __MWERKS__ | 64 #if __MWERKS__ |
81 #include <unistd.h> | 65 #include <unistd.h> |
82 #endif | 66 #endif |
83 | |
84 #include "lisp.h" | |
85 #include "process.h" | |
86 #include "sysselect.h" | |
87 #include "systime.h" | |
88 #include "blockinput.h" | |
89 | 67 |
90 Lisp_Object QCLIPBOARD; | 68 Lisp_Object QCLIPBOARD; |
91 | 69 |
92 /* An instance of the AppleScript component. */ | 70 /* An instance of the AppleScript component. */ |
93 static ComponentInstance as_scripting_component; | 71 static ComponentInstance as_scripting_component; |
270 } | 248 } |
271 | 249 |
272 return 1; | 250 return 1; |
273 } | 251 } |
274 | 252 |
253 | |
254 /*********************************************************************** | |
255 Conversion between Lisp and Core Foundation objects | |
256 ***********************************************************************/ | |
257 | |
275 #if TARGET_API_MAC_CARBON | 258 #if TARGET_API_MAC_CARBON |
259 static Lisp_Object Qstring, Qnumber, Qboolean, Qdate, Qdata; | |
260 static Lisp_Object Qarray, Qdictionary; | |
261 extern Lisp_Object Qutf_8; | |
262 #define DECODE_UTF_8(str) code_convert_string_norecord (str, Qutf_8, 0) | |
263 | |
264 struct cfdict_context | |
265 { | |
266 Lisp_Object *result; | |
267 int with_tag, hash_bound; | |
268 }; | |
269 | |
270 /* C string to CFString. */ | |
271 | |
276 CFStringRef | 272 CFStringRef |
277 cfstring_create_with_utf8_cstring (c_str) | 273 cfstring_create_with_utf8_cstring (c_str) |
278 const char *c_str; | 274 const char *c_str; |
279 { | 275 { |
280 CFStringRef str; | 276 CFStringRef str; |
284 /* Failed to interpret as UTF 8. Fall back on Mac Roman. */ | 280 /* Failed to interpret as UTF 8. Fall back on Mac Roman. */ |
285 str = CFStringCreateWithCString (NULL, c_str, kCFStringEncodingMacRoman); | 281 str = CFStringCreateWithCString (NULL, c_str, kCFStringEncodingMacRoman); |
286 | 282 |
287 return str; | 283 return str; |
288 } | 284 } |
285 | |
286 | |
287 /* From CFData to a lisp string. Always returns a unibyte string. */ | |
288 | |
289 Lisp_Object | |
290 cfdata_to_lisp (data) | |
291 CFDataRef data; | |
292 { | |
293 CFIndex len = CFDataGetLength (data); | |
294 Lisp_Object result = make_uninit_string (len); | |
295 | |
296 CFDataGetBytes (data, CFRangeMake (0, len), SDATA (result)); | |
297 | |
298 return result; | |
299 } | |
300 | |
301 | |
302 /* From CFString to a lisp string. Never returns a unibyte string | |
303 (even if it only contains ASCII characters). | |
304 This may cause GC during code conversion. */ | |
305 | |
306 Lisp_Object | |
307 cfstring_to_lisp (string) | |
308 CFStringRef string; | |
309 { | |
310 Lisp_Object result = Qnil; | |
311 const char *s = CFStringGetCStringPtr (string, kCFStringEncodingUTF8); | |
312 | |
313 if (s) | |
314 result = make_unibyte_string (s, strlen (s)); | |
315 else | |
316 { | |
317 CFDataRef data = | |
318 CFStringCreateExternalRepresentation (NULL, string, | |
319 kCFStringEncodingUTF8, '?'); | |
320 | |
321 if (data) | |
322 { | |
323 result = cfdata_to_lisp (data); | |
324 CFRelease (data); | |
325 } | |
326 } | |
327 | |
328 if (!NILP (result)) | |
329 { | |
330 result = DECODE_UTF_8 (result); | |
331 /* This may be superfluous. Just to make sure that the result | |
332 is a multibyte string. */ | |
333 result = string_to_multibyte (result); | |
334 } | |
335 | |
336 return result; | |
337 } | |
338 | |
339 | |
340 /* CFNumber to a lisp integer or a lisp float. */ | |
341 | |
342 Lisp_Object | |
343 cfnumber_to_lisp (number) | |
344 CFNumberRef number; | |
345 { | |
346 Lisp_Object result = Qnil; | |
347 #if BITS_PER_EMACS_INT > 32 | |
348 SInt64 int_val; | |
349 CFNumberType emacs_int_type = kCFNumberSInt64Type; | |
350 #else | |
351 SInt32 int_val; | |
352 CFNumberType emacs_int_type = kCFNumberSInt32Type; | |
289 #endif | 353 #endif |
290 | 354 double float_val; |
355 | |
356 if (CFNumberGetValue (number, emacs_int_type, &int_val) | |
357 && !FIXNUM_OVERFLOW_P (int_val)) | |
358 result = make_number (int_val); | |
359 else | |
360 if (CFNumberGetValue (number, kCFNumberDoubleType, &float_val)) | |
361 result = make_float (float_val); | |
362 return result; | |
363 } | |
364 | |
365 | |
366 /* CFDate to a list of three integers as in a return value of | |
367 `current-time'xo. */ | |
368 | |
369 Lisp_Object | |
370 cfdate_to_lisp (date) | |
371 CFDateRef date; | |
372 { | |
373 static CFGregorianDate epoch_gdate = {1970, 1, 1, 0, 0, 0.0}; | |
374 static CFAbsoluteTime epoch = 0.0, sec; | |
375 int high, low; | |
376 | |
377 if (epoch == 0.0) | |
378 epoch = CFGregorianDateGetAbsoluteTime (epoch_gdate, NULL); | |
379 | |
380 sec = CFDateGetAbsoluteTime (date) - epoch; | |
381 high = sec / 65536.0; | |
382 low = sec - high * 65536.0; | |
383 | |
384 return list3 (make_number (high), make_number (low), make_number (0)); | |
385 } | |
386 | |
387 | |
388 /* CFBoolean to a lisp symbol, `t' or `nil'. */ | |
389 | |
390 Lisp_Object | |
391 cfboolean_to_lisp (boolean) | |
392 CFBooleanRef boolean; | |
393 { | |
394 return CFBooleanGetValue (boolean) ? Qt : Qnil; | |
395 } | |
396 | |
397 | |
398 /* Any Core Foundation object to a (lengthy) lisp string. */ | |
399 | |
400 Lisp_Object | |
401 cfobject_desc_to_lisp (object) | |
402 CFTypeRef object; | |
403 { | |
404 Lisp_Object result = Qnil; | |
405 CFStringRef desc = CFCopyDescription (object); | |
406 | |
407 if (desc) | |
408 { | |
409 result = cfstring_to_lisp (desc); | |
410 CFRelease (desc); | |
411 } | |
412 | |
413 return result; | |
414 } | |
415 | |
416 | |
417 /* Callback functions for cfproperty_list_to_lisp. */ | |
418 | |
419 static void | |
420 cfdictionary_add_to_list (key, value, context) | |
421 const void *key; | |
422 const void *value; | |
423 void *context; | |
424 { | |
425 struct cfdict_context *cxt = (struct cfdict_context *)context; | |
426 | |
427 *cxt->result = | |
428 Fcons (Fcons (cfstring_to_lisp (key), | |
429 cfproperty_list_to_lisp (value, cxt->with_tag, | |
430 cxt->hash_bound)), | |
431 *cxt->result); | |
432 } | |
433 | |
434 static void | |
435 cfdictionary_puthash (key, value, context) | |
436 const void *key; | |
437 const void *value; | |
438 void *context; | |
439 { | |
440 Lisp_Object lisp_key = cfstring_to_lisp (key); | |
441 struct cfdict_context *cxt = (struct cfdict_context *)context; | |
442 struct Lisp_Hash_Table *h = XHASH_TABLE (*(cxt->result)); | |
443 unsigned hash_code; | |
444 | |
445 hash_lookup (h, lisp_key, &hash_code); | |
446 hash_put (h, lisp_key, | |
447 cfproperty_list_to_lisp (value, cxt->with_tag, cxt->hash_bound), | |
448 hash_code); | |
449 } | |
450 | |
451 | |
452 /* Convert CFPropertyList PLIST to a lisp object. If WITH_TAG is | |
453 non-zero, a symbol that represents the type of the original Core | |
454 Foundation object is prepended. HASH_BOUND specifies which kinds | |
455 of the lisp objects, alists or hash tables, are used as the targets | |
456 of the conversion from CFDictionary. If HASH_BOUND is negative, | |
457 always generate alists. If HASH_BOUND >= 0, generate an alist if | |
458 the number of keys in the dictionary is smaller than HASH_BOUND, | |
459 and a hash table otherwise. */ | |
460 | |
461 Lisp_Object | |
462 cfproperty_list_to_lisp (plist, with_tag, hash_bound) | |
463 CFPropertyListRef plist; | |
464 int with_tag, hash_bound; | |
465 { | |
466 CFTypeID type_id = CFGetTypeID (plist); | |
467 Lisp_Object tag = Qnil, result = Qnil; | |
468 struct gcpro gcpro1, gcpro2; | |
469 | |
470 GCPRO2 (tag, result); | |
471 | |
472 if (type_id == CFStringGetTypeID ()) | |
473 { | |
474 tag = Qstring; | |
475 result = cfstring_to_lisp (plist); | |
476 } | |
477 else if (type_id == CFNumberGetTypeID ()) | |
478 { | |
479 tag = Qnumber; | |
480 result = cfnumber_to_lisp (plist); | |
481 } | |
482 else if (type_id == CFBooleanGetTypeID ()) | |
483 { | |
484 tag = Qboolean; | |
485 result = cfboolean_to_lisp (plist); | |
486 } | |
487 else if (type_id == CFDateGetTypeID ()) | |
488 { | |
489 tag = Qdate; | |
490 result = cfdate_to_lisp (plist); | |
491 } | |
492 else if (type_id == CFDataGetTypeID ()) | |
493 { | |
494 tag = Qdata; | |
495 result = cfdata_to_lisp (plist); | |
496 } | |
497 else if (type_id == CFArrayGetTypeID ()) | |
498 { | |
499 CFIndex index, count = CFArrayGetCount (plist); | |
500 | |
501 tag = Qarray; | |
502 result = Fmake_vector (make_number (count), Qnil); | |
503 for (index = 0; index < count; index++) | |
504 XVECTOR (result)->contents[index] = | |
505 cfproperty_list_to_lisp (CFArrayGetValueAtIndex (plist, index), | |
506 with_tag, hash_bound); | |
507 } | |
508 else if (type_id == CFDictionaryGetTypeID ()) | |
509 { | |
510 struct cfdict_context context; | |
511 CFIndex count = CFDictionaryGetCount (plist); | |
512 | |
513 tag = Qdictionary; | |
514 context.result = &result; | |
515 context.with_tag = with_tag; | |
516 context.hash_bound = hash_bound; | |
517 if (hash_bound < 0 || count < hash_bound) | |
518 { | |
519 result = Qnil; | |
520 CFDictionaryApplyFunction (plist, cfdictionary_add_to_list, | |
521 &context); | |
522 } | |
523 else | |
524 { | |
525 result = make_hash_table (Qequal, | |
526 make_number (count), | |
527 make_float (DEFAULT_REHASH_SIZE), | |
528 make_float (DEFAULT_REHASH_THRESHOLD), | |
529 Qnil, Qnil, Qnil); | |
530 CFDictionaryApplyFunction (plist, cfdictionary_puthash, | |
531 &context); | |
532 } | |
533 } | |
534 else | |
535 abort (); | |
536 | |
537 UNGCPRO; | |
538 | |
539 if (with_tag) | |
540 result = Fcons (tag, result); | |
541 | |
542 return result; | |
543 } | |
544 #endif | |
545 | |
546 | |
547 /*********************************************************************** | |
548 Emulation of the X Resource Manager | |
549 ***********************************************************************/ | |
550 | |
551 /* Parser functions for resource lines. Each function takes an | |
552 address of a variable whose value points to the head of a string. | |
553 The value will be advanced so that it points to the next character | |
554 of the parsed part when the function returns. | |
555 | |
556 A resource name such as "Emacs*font" is parsed into a non-empty | |
557 list called `quarks'. Each element is either a Lisp string that | |
558 represents a concrete component, a Lisp symbol LOOSE_BINDING | |
559 (actually Qlambda) that represents any number (>=0) of intervening | |
560 components, or a Lisp symbol SINGLE_COMPONENT (actually Qquote) | |
561 that represents as any single component. */ | |
562 | |
563 #define P (*p) | |
564 | |
565 #define LOOSE_BINDING Qlambda /* '*' ("L"oose) */ | |
566 #define SINGLE_COMPONENT Qquote /* '?' ("Q"uestion) */ | |
567 | |
568 static void | |
569 skip_white_space (p) | |
570 char **p; | |
571 { | |
572 /* WhiteSpace = {<space> | <horizontal tab>} */ | |
573 while (*P == ' ' || *P == '\t') | |
574 P++; | |
575 } | |
576 | |
577 static int | |
578 parse_comment (p) | |
579 char **p; | |
580 { | |
581 /* Comment = "!" {<any character except null or newline>} */ | |
582 if (*P == '!') | |
583 { | |
584 P++; | |
585 while (*P) | |
586 if (*P++ == '\n') | |
587 break; | |
588 return 1; | |
589 } | |
590 else | |
591 return 0; | |
592 } | |
593 | |
594 /* Don't interpret filename. Just skip until the newline. */ | |
595 static int | |
596 parse_include_file (p) | |
597 char **p; | |
598 { | |
599 /* IncludeFile = "#" WhiteSpace "include" WhiteSpace FileName WhiteSpace */ | |
600 if (*P == '#') | |
601 { | |
602 P++; | |
603 while (*P) | |
604 if (*P++ == '\n') | |
605 break; | |
606 return 1; | |
607 } | |
608 else | |
609 return 0; | |
610 } | |
611 | |
612 static char | |
613 parse_binding (p) | |
614 char **p; | |
615 { | |
616 /* Binding = "." | "*" */ | |
617 if (*P == '.' || *P == '*') | |
618 { | |
619 char binding = *P++; | |
620 | |
621 while (*P == '.' || *P == '*') | |
622 if (*P++ == '*') | |
623 binding = '*'; | |
624 return binding; | |
625 } | |
626 else | |
627 return '\0'; | |
628 } | |
629 | |
630 static Lisp_Object | |
631 parse_component (p) | |
632 char **p; | |
633 { | |
634 /* Component = "?" | ComponentName | |
635 ComponentName = NameChar {NameChar} | |
636 NameChar = "a"-"z" | "A"-"Z" | "0"-"9" | "_" | "-" */ | |
637 if (*P == '?') | |
638 { | |
639 P++; | |
640 return SINGLE_COMPONENT; | |
641 } | |
642 else if (isalnum (*P) || *P == '_' || *P == '-') | |
643 { | |
644 char *start = P++; | |
645 | |
646 while (isalnum (*P) || *P == '_' || *P == '-') | |
647 P++; | |
648 | |
649 return make_unibyte_string (start, P - start); | |
650 } | |
651 else | |
652 return Qnil; | |
653 } | |
654 | |
655 static Lisp_Object | |
656 parse_resource_name (p) | |
657 char **p; | |
658 { | |
659 Lisp_Object result = Qnil, component; | |
660 char binding; | |
661 | |
662 /* ResourceName = [Binding] {Component Binding} ComponentName */ | |
663 if (parse_binding (p) == '*') | |
664 result = Fcons (LOOSE_BINDING, result); | |
665 | |
666 component = parse_component (p); | |
667 if (NILP (component)) | |
668 return Qnil; | |
669 | |
670 result = Fcons (component, result); | |
671 while (binding = parse_binding (p)) | |
672 { | |
673 if (binding == '*') | |
674 result = Fcons (LOOSE_BINDING, result); | |
675 component = parse_component (p); | |
676 if (NILP (component)) | |
677 return Qnil; | |
678 else | |
679 result = Fcons (component, result); | |
680 } | |
681 | |
682 /* The final component should not be '?'. */ | |
683 if (EQ (component, SINGLE_COMPONENT)) | |
684 return Qnil; | |
685 | |
686 return Fnreverse (result); | |
687 } | |
688 | |
689 static Lisp_Object | |
690 parse_value (p) | |
691 char **p; | |
692 { | |
693 char *q, *buf; | |
694 Lisp_Object seq = Qnil, result; | |
695 int buf_len, total_len = 0, len, continue_p; | |
696 | |
697 q = strchr (P, '\n'); | |
698 buf_len = q ? q - P : strlen (P); | |
699 buf = xmalloc (buf_len); | |
700 | |
701 while (1) | |
702 { | |
703 q = buf; | |
704 continue_p = 0; | |
705 while (*P) | |
706 { | |
707 if (*P == '\n') | |
708 { | |
709 P++; | |
710 break; | |
711 } | |
712 else if (*P == '\\') | |
713 { | |
714 P++; | |
715 if (*P == '\0') | |
716 break; | |
717 else if (*P == '\n') | |
718 { | |
719 P++; | |
720 continue_p = 1; | |
721 break; | |
722 } | |
723 else if (*P == 'n') | |
724 { | |
725 *q++ = '\n'; | |
726 P++; | |
727 } | |
728 else if ('0' <= P[0] && P[0] <= '7' | |
729 && '0' <= P[1] && P[1] <= '7' | |
730 && '0' <= P[2] && P[2] <= '7') | |
731 { | |
732 *q++ = (P[0] - '0' << 6) + (P[1] - '0' << 3) + (P[2] - '0'); | |
733 P += 3; | |
734 } | |
735 else | |
736 *q++ = *P++; | |
737 } | |
738 else | |
739 *q++ = *P++; | |
740 } | |
741 len = q - buf; | |
742 seq = Fcons (make_unibyte_string (buf, len), seq); | |
743 total_len += len; | |
744 | |
745 if (continue_p) | |
746 { | |
747 q = strchr (P, '\n'); | |
748 len = q ? q - P : strlen (P); | |
749 if (len > buf_len) | |
750 { | |
751 xfree (buf); | |
752 buf_len = len; | |
753 buf = xmalloc (buf_len); | |
754 } | |
755 } | |
756 else | |
757 break; | |
758 } | |
759 xfree (buf); | |
760 | |
761 if (SBYTES (XCAR (seq)) == total_len) | |
762 return make_string (SDATA (XCAR (seq)), total_len); | |
763 else | |
764 { | |
765 buf = xmalloc (total_len); | |
766 q = buf + total_len; | |
767 for (; CONSP (seq); seq = XCDR (seq)) | |
768 { | |
769 len = SBYTES (XCAR (seq)); | |
770 q -= len; | |
771 memcpy (q, SDATA (XCAR (seq)), len); | |
772 } | |
773 result = make_string (buf, total_len); | |
774 xfree (buf); | |
775 return result; | |
776 } | |
777 } | |
778 | |
779 static Lisp_Object | |
780 parse_resource_line (p) | |
781 char **p; | |
782 { | |
783 Lisp_Object quarks, value; | |
784 | |
785 /* ResourceLine = Comment | IncludeFile | ResourceSpec | <empty line> */ | |
786 if (parse_comment (p) || parse_include_file (p)) | |
787 return Qnil; | |
788 | |
789 /* ResourceSpec = WhiteSpace ResourceName WhiteSpace ":" WhiteSpace Value */ | |
790 skip_white_space (p); | |
791 quarks = parse_resource_name (p); | |
792 if (NILP (quarks)) | |
793 goto cleanup; | |
794 skip_white_space (p); | |
795 if (*P != ':') | |
796 goto cleanup; | |
797 P++; | |
798 skip_white_space (p); | |
799 value = parse_value (p); | |
800 return Fcons (quarks, value); | |
801 | |
802 cleanup: | |
803 /* Skip the remaining data as a dummy value. */ | |
804 parse_value (p); | |
805 return Qnil; | |
806 } | |
807 | |
808 #undef P | |
809 | |
810 /* Equivalents of X Resource Manager functions. | |
811 | |
812 An X Resource Database acts as a collection of resource names and | |
813 associated values. It is implemented as a trie on quarks. Namely, | |
814 each edge is labeled by either a string, LOOSE_BINDING, or | |
815 SINGLE_COMPONENT. Each node has a node id, which is a unique | |
816 nonnegative integer, and the root node id is 0. A database is | |
817 implemented as a hash table that maps a pair (SRC-NODE-ID . | |
818 EDGE-LABEL) to DEST-NODE-ID. It also holds a maximum node id used | |
819 in the table as a value for HASHKEY_MAX_NID. A value associated to | |
820 a node is recorded as a value for the node id. */ | |
821 | |
822 #define HASHKEY_MAX_NID (make_number (0)) | |
823 | |
824 static XrmDatabase | |
825 xrm_create_database () | |
826 { | |
827 XrmDatabase database; | |
828 | |
829 database = make_hash_table (Qequal, make_number (DEFAULT_HASH_SIZE), | |
830 make_float (DEFAULT_REHASH_SIZE), | |
831 make_float (DEFAULT_REHASH_THRESHOLD), | |
832 Qnil, Qnil, Qnil); | |
833 Fputhash (HASHKEY_MAX_NID, make_number (0), database); | |
834 | |
835 return database; | |
836 } | |
837 | |
838 static void | |
839 xrm_q_put_resource (database, quarks, value) | |
840 XrmDatabase database; | |
841 Lisp_Object quarks, value; | |
842 { | |
843 struct Lisp_Hash_Table *h = XHASH_TABLE (database); | |
844 unsigned hash_code; | |
845 int max_nid, i; | |
846 Lisp_Object node_id, key; | |
847 | |
848 max_nid = XINT (Fgethash (HASHKEY_MAX_NID, database, Qnil)); | |
849 | |
850 XSETINT (node_id, 0); | |
851 for (; CONSP (quarks); quarks = XCDR (quarks)) | |
852 { | |
853 key = Fcons (node_id, XCAR (quarks)); | |
854 i = hash_lookup (h, key, &hash_code); | |
855 if (i < 0) | |
856 { | |
857 max_nid++; | |
858 XSETINT (node_id, max_nid); | |
859 hash_put (h, key, node_id, hash_code); | |
860 } | |
861 else | |
862 node_id = HASH_VALUE (h, i); | |
863 } | |
864 Fputhash (node_id, value, database); | |
865 | |
866 Fputhash (HASHKEY_MAX_NID, make_number (max_nid), database); | |
867 } | |
868 | |
869 /* Merge multiple resource entries specified by DATA into a resource | |
870 database DATABASE. DATA points to the head of a null-terminated | |
871 string consisting of multiple resource lines. It's like a | |
872 combination of XrmGetStringDatabase and XrmMergeDatabases. */ | |
873 | |
874 void | |
875 xrm_merge_string_database (database, data) | |
876 XrmDatabase database; | |
877 char *data; | |
878 { | |
879 Lisp_Object quarks_value; | |
880 | |
881 while (*data) | |
882 { | |
883 quarks_value = parse_resource_line (&data); | |
884 if (!NILP (quarks_value)) | |
885 xrm_q_put_resource (database, | |
886 XCAR (quarks_value), XCDR (quarks_value)); | |
887 } | |
888 } | |
889 | |
890 static Lisp_Object | |
891 xrm_q_get_resource_1 (database, node_id, quark_name, quark_class) | |
892 XrmDatabase database; | |
893 Lisp_Object node_id, quark_name, quark_class; | |
894 { | |
895 struct Lisp_Hash_Table *h = XHASH_TABLE (database); | |
896 Lisp_Object key, labels[3], value; | |
897 int i, k; | |
898 | |
899 if (!CONSP (quark_name)) | |
900 return Fgethash (node_id, database, Qnil); | |
901 | |
902 /* First, try tight bindings */ | |
903 labels[0] = XCAR (quark_name); | |
904 labels[1] = XCAR (quark_class); | |
905 labels[2] = SINGLE_COMPONENT; | |
906 | |
907 key = Fcons (node_id, Qnil); | |
908 for (k = 0; k < sizeof (labels) / sizeof (*labels); k++) | |
909 { | |
910 XSETCDR (key, labels[k]); | |
911 i = hash_lookup (h, key, NULL); | |
912 if (i >= 0) | |
913 { | |
914 value = xrm_q_get_resource_1 (database, HASH_VALUE (h, i), | |
915 XCDR (quark_name), XCDR (quark_class)); | |
916 if (!NILP (value)) | |
917 return value; | |
918 } | |
919 } | |
920 | |
921 /* Then, try loose bindings */ | |
922 XSETCDR (key, LOOSE_BINDING); | |
923 i = hash_lookup (h, key, NULL); | |
924 if (i >= 0) | |
925 { | |
926 value = xrm_q_get_resource_1 (database, HASH_VALUE (h, i), | |
927 quark_name, quark_class); | |
928 if (!NILP (value)) | |
929 return value; | |
930 else | |
931 return xrm_q_get_resource_1 (database, node_id, | |
932 XCDR (quark_name), XCDR (quark_class)); | |
933 } | |
934 else | |
935 return Qnil; | |
936 } | |
937 | |
938 static Lisp_Object | |
939 xrm_q_get_resource (database, quark_name, quark_class) | |
940 XrmDatabase database; | |
941 Lisp_Object quark_name, quark_class; | |
942 { | |
943 return xrm_q_get_resource_1 (database, make_number (0), | |
944 quark_name, quark_class); | |
945 } | |
946 | |
947 /* Retrieve a resource value for the specified NAME and CLASS from the | |
948 resource database DATABASE. It corresponds to XrmGetResource. */ | |
949 | |
950 Lisp_Object | |
951 xrm_get_resource (database, name, class) | |
952 XrmDatabase database; | |
953 char *name, *class; | |
954 { | |
955 Lisp_Object quark_name, quark_class, tmp; | |
956 int nn, nc; | |
957 | |
958 quark_name = parse_resource_name (&name); | |
959 if (*name != '\0') | |
960 return Qnil; | |
961 for (tmp = quark_name, nn = 0; CONSP (tmp); tmp = XCDR (tmp), nn++) | |
962 if (!STRINGP (XCAR (tmp))) | |
963 return Qnil; | |
964 | |
965 quark_class = parse_resource_name (&class); | |
966 if (*class != '\0') | |
967 return Qnil; | |
968 for (tmp = quark_class, nc = 0; CONSP (tmp); tmp = XCDR (tmp), nc++) | |
969 if (!STRINGP (XCAR (tmp))) | |
970 return Qnil; | |
971 | |
972 if (nn != nc) | |
973 return Qnil; | |
974 else | |
975 return xrm_q_get_resource (database, quark_name, quark_class); | |
976 } | |
977 | |
978 #if TARGET_API_MAC_CARBON | |
979 static Lisp_Object | |
980 xrm_cfproperty_list_to_value (plist) | |
981 CFPropertyListRef plist; | |
982 { | |
983 CFTypeID type_id = CFGetTypeID (plist); | |
984 | |
985 if (type_id == CFStringGetTypeID ()) | |
986 return cfstring_to_lisp (plist); | |
987 else if (type_id == CFNumberGetTypeID ()) | |
988 { | |
989 CFStringRef string; | |
990 Lisp_Object result = Qnil; | |
991 | |
992 string = CFStringCreateWithFormat (NULL, NULL, CFSTR ("%@"), plist); | |
993 if (string) | |
994 { | |
995 result = cfstring_to_lisp (string); | |
996 CFRelease (string); | |
997 } | |
998 return result; | |
999 } | |
1000 else if (type_id == CFBooleanGetTypeID ()) | |
1001 return build_string (CFBooleanGetValue (plist) ? "true" : "false"); | |
1002 else if (type_id == CFDataGetTypeID ()) | |
1003 return cfdata_to_lisp (plist); | |
1004 else | |
1005 return Qnil; | |
1006 } | |
1007 #endif | |
1008 | |
1009 /* Create a new resource database from the preferences for the | |
1010 application APPLICATION. APPLICATION is either a string that | |
1011 specifies an application ID, or NULL that represents the current | |
1012 application. */ | |
1013 | |
1014 XrmDatabase | |
1015 xrm_get_preference_database (application) | |
1016 char *application; | |
1017 { | |
1018 #if TARGET_API_MAC_CARBON | |
1019 CFStringRef app_id, *keys, user_doms[2], host_doms[2]; | |
1020 CFMutableSetRef key_set = NULL; | |
1021 CFArrayRef key_array; | |
1022 CFIndex index, count; | |
1023 char *res_name; | |
1024 XrmDatabase database; | |
1025 Lisp_Object quarks = Qnil, value = Qnil; | |
1026 CFPropertyListRef plist; | |
1027 int iu, ih; | |
1028 struct gcpro gcpro1, gcpro2, gcpro3; | |
1029 | |
1030 user_doms[0] = kCFPreferencesCurrentUser; | |
1031 user_doms[1] = kCFPreferencesAnyUser; | |
1032 host_doms[0] = kCFPreferencesCurrentHost; | |
1033 host_doms[1] = kCFPreferencesAnyHost; | |
1034 | |
1035 database = xrm_create_database (); | |
1036 | |
1037 GCPRO3 (database, quarks, value); | |
1038 | |
1039 BLOCK_INPUT; | |
1040 | |
1041 app_id = kCFPreferencesCurrentApplication; | |
1042 if (application) | |
1043 { | |
1044 app_id = cfstring_create_with_utf8_cstring (application); | |
1045 if (app_id == NULL) | |
1046 goto out; | |
1047 } | |
1048 | |
1049 key_set = CFSetCreateMutable (NULL, 0, &kCFCopyStringSetCallBacks); | |
1050 if (key_set == NULL) | |
1051 goto out; | |
1052 for (iu = 0; iu < sizeof (user_doms) / sizeof (*user_doms) ; iu++) | |
1053 for (ih = 0; ih < sizeof (host_doms) / sizeof (*host_doms); ih++) | |
1054 { | |
1055 key_array = CFPreferencesCopyKeyList (app_id, user_doms[iu], | |
1056 host_doms[ih]); | |
1057 if (key_array) | |
1058 { | |
1059 count = CFArrayGetCount (key_array); | |
1060 for (index = 0; index < count; index++) | |
1061 CFSetAddValue (key_set, | |
1062 CFArrayGetValueAtIndex (key_array, index)); | |
1063 CFRelease (key_array); | |
1064 } | |
1065 } | |
1066 | |
1067 count = CFSetGetCount (key_set); | |
1068 keys = xmalloc (sizeof (CFStringRef) * count); | |
1069 if (keys == NULL) | |
1070 goto out; | |
1071 CFSetGetValues (key_set, (const void **)keys); | |
1072 for (index = 0; index < count; index++) | |
1073 { | |
1074 res_name = SDATA (cfstring_to_lisp (keys[index])); | |
1075 quarks = parse_resource_name (&res_name); | |
1076 if (!(NILP (quarks) || *res_name)) | |
1077 { | |
1078 plist = CFPreferencesCopyAppValue (keys[index], app_id); | |
1079 value = xrm_cfproperty_list_to_value (plist); | |
1080 CFRelease (plist); | |
1081 if (!NILP (value)) | |
1082 xrm_q_put_resource (database, quarks, value); | |
1083 } | |
1084 } | |
1085 | |
1086 xfree (keys); | |
1087 out: | |
1088 if (key_set) | |
1089 CFRelease (key_set); | |
1090 CFRelease (app_id); | |
1091 | |
1092 UNBLOCK_INPUT; | |
1093 | |
1094 UNGCPRO; | |
1095 | |
1096 return database; | |
1097 #else | |
1098 return xrm_create_database (); | |
1099 #endif | |
1100 } | |
1101 | |
1102 | |
291 #ifndef MAC_OSX | 1103 #ifndef MAC_OSX |
292 | 1104 |
293 /* The following functions with "sys_" prefix are stubs to Unix | 1105 /* The following functions with "sys_" prefix are stubs to Unix |
294 functions that have already been implemented by CW or MPW. The | 1106 functions that have already been implemented by CW or MPW. The |
295 calls to them in Emacs source course are #define'd to call the sys_ | 1107 calls to them in Emacs source course are #define'd to call the sys_ |
2823 return val; | 3635 return val; |
2824 } | 3636 } |
2825 return Qnil; | 3637 return Qnil; |
2826 } | 3638 } |
2827 | 3639 |
3640 #if TARGET_API_MAC_CARBON | |
3641 static Lisp_Object Qxml; | |
3642 | |
3643 DEFUN ("mac-get-preference", Fmac_get_preference, Smac_get_preference, 1, 4, 0, | |
3644 doc: /* Return the application preference value for KEY. | |
3645 KEY is either a string specifying a preference key, or a list of key | |
3646 strings. If it is a list, the (i+1)-th element is used as a key for | |
3647 the CFDictionary value obtained by the i-th element. If lookup is | |
3648 failed at some stage, nil is returned. | |
3649 | |
3650 Optional arg APPLICATION is an application ID string. If omitted or | |
3651 nil, that stands for the current application. | |
3652 | |
3653 Optional arg FORMAT specifies the data format of the return value. If | |
3654 omitted or nil, each Core Foundation object is converted into a | |
3655 corresponding Lisp object as follows: | |
3656 | |
3657 Core Foundation Lisp Tag | |
3658 ------------------------------------------------------------ | |
3659 CFString Multibyte string string | |
3660 CFNumber Integer or float number | |
3661 CFBoolean Symbol (t or nil) boolean | |
3662 CFDate List of three integers date | |
3663 (cf. `current-time') | |
3664 CFData Unibyte string data | |
3665 CFArray Array array | |
3666 CFDictionary Alist or hash table dictionary | |
3667 (depending on HASH-BOUND) | |
3668 | |
3669 If it is t, a symbol that represents the type of the original Core | |
3670 Foundation object is prepended. If it is `xml', the value is returned | |
3671 as an XML representation. | |
3672 | |
3673 Optional arg HASH-BOUND specifies which kinds of the list objects, | |
3674 alists or hash tables, are used as the targets of the conversion from | |
3675 CFDictionary. If HASH-BOUND is a negative integer or nil, always | |
3676 generate alists. If HASH-BOUND >= 0, generate an alist if the number | |
3677 of keys in the dictionary is smaller than HASH-BOUND, and a hash table | |
3678 otherwise. */) | |
3679 (key, application, format, hash_bound) | |
3680 Lisp_Object key, application, format, hash_bound; | |
3681 { | |
3682 CFStringRef app_id, key_str; | |
3683 CFPropertyListRef app_plist = NULL, plist; | |
3684 Lisp_Object result = Qnil, tmp; | |
3685 | |
3686 if (STRINGP (key)) | |
3687 key = Fcons (key, Qnil); | |
3688 else | |
3689 { | |
3690 CHECK_CONS (key); | |
3691 for (tmp = key; CONSP (tmp); tmp = XCDR (tmp)) | |
3692 CHECK_STRING_CAR (tmp); | |
3693 if (!NILP (tmp)) | |
3694 wrong_type_argument (Qlistp, key); | |
3695 } | |
3696 if (!NILP (application)) | |
3697 CHECK_STRING (application); | |
3698 CHECK_SYMBOL (format); | |
3699 if (!NILP (hash_bound)) | |
3700 CHECK_NUMBER (hash_bound); | |
3701 | |
3702 BLOCK_INPUT; | |
3703 | |
3704 app_id = kCFPreferencesCurrentApplication; | |
3705 if (!NILP (application)) | |
3706 { | |
3707 app_id = cfstring_create_with_utf8_cstring (SDATA (application)); | |
3708 if (app_id == NULL) | |
3709 goto out; | |
3710 } | |
3711 key_str = cfstring_create_with_utf8_cstring (SDATA (XCAR (key))); | |
3712 if (key_str == NULL) | |
3713 goto out; | |
3714 app_plist = CFPreferencesCopyAppValue (key_str, app_id); | |
3715 CFRelease (key_str); | |
3716 if (app_plist == NULL) | |
3717 goto out; | |
3718 | |
3719 plist = app_plist; | |
3720 for (key = XCDR (key); CONSP (key); key = XCDR (key)) | |
3721 { | |
3722 if (CFGetTypeID (plist) != CFDictionaryGetTypeID ()) | |
3723 break; | |
3724 key_str = cfstring_create_with_utf8_cstring (SDATA (XCAR (key))); | |
3725 if (key_str == NULL) | |
3726 goto out; | |
3727 plist = CFDictionaryGetValue (plist, key_str); | |
3728 CFRelease (key_str); | |
3729 if (plist == NULL) | |
3730 goto out; | |
3731 } | |
3732 | |
3733 if (NILP (key)) | |
3734 if (EQ (format, Qxml)) | |
3735 { | |
3736 CFDataRef data = CFPropertyListCreateXMLData (NULL, plist); | |
3737 if (data == NULL) | |
3738 goto out; | |
3739 result = cfdata_to_lisp (data); | |
3740 CFRelease (data); | |
3741 } | |
3742 else | |
3743 result = | |
3744 cfproperty_list_to_lisp (plist, EQ (format, Qt), | |
3745 NILP (hash_bound) ? -1 : XINT (hash_bound)); | |
3746 | |
3747 out: | |
3748 if (app_plist) | |
3749 CFRelease (app_plist); | |
3750 CFRelease (app_id); | |
3751 | |
3752 UNBLOCK_INPUT; | |
3753 | |
3754 return result; | |
3755 } | |
3756 #endif /* TARGET_API_MAC_CARBON */ | |
3757 | |
2828 | 3758 |
2829 DEFUN ("mac-clear-font-name-table", Fmac_clear_font_name_table, Smac_clear_font_name_table, 0, 0, 0, | 3759 DEFUN ("mac-clear-font-name-table", Fmac_clear_font_name_table, Smac_clear_font_name_table, 0, 0, 0, |
2830 doc: /* Clear the font name table. */) | 3760 doc: /* Clear the font name table. */) |
2831 () | 3761 () |
2832 { | 3762 { |
3241 syms_of_mac () | 4171 syms_of_mac () |
3242 { | 4172 { |
3243 QCLIPBOARD = intern ("CLIPBOARD"); | 4173 QCLIPBOARD = intern ("CLIPBOARD"); |
3244 staticpro (&QCLIPBOARD); | 4174 staticpro (&QCLIPBOARD); |
3245 | 4175 |
4176 #if TARGET_API_MAC_CARBON | |
4177 Qstring = intern ("string"); | |
4178 staticpro (&Qstring); | |
4179 | |
4180 Qnumber = intern ("number"); | |
4181 staticpro (&Qnumber); | |
4182 | |
4183 Qboolean = intern ("boolean"); | |
4184 staticpro (&Qboolean); | |
4185 | |
4186 Qdate = intern ("date"); | |
4187 staticpro (&Qdate); | |
4188 | |
4189 Qdata = intern ("data"); | |
4190 staticpro (&Qdata); | |
4191 | |
4192 Qarray = intern ("array"); | |
4193 staticpro (&Qarray); | |
4194 | |
4195 Qdictionary = intern ("dictionary"); | |
4196 staticpro (&Qdictionary); | |
4197 | |
4198 Qxml = intern ("xml"); | |
4199 staticpro (&Qxml); | |
4200 #endif | |
4201 | |
3246 defsubr (&Smac_paste_function); | 4202 defsubr (&Smac_paste_function); |
3247 defsubr (&Smac_cut_function); | 4203 defsubr (&Smac_cut_function); |
3248 defsubr (&Sx_selection_exists_p); | 4204 defsubr (&Sx_selection_exists_p); |
4205 #if TARGET_API_MAC_CARBON | |
4206 defsubr (&Smac_get_preference); | |
4207 #endif | |
3249 defsubr (&Smac_clear_font_name_table); | 4208 defsubr (&Smac_clear_font_name_table); |
3250 | 4209 |
3251 defsubr (&Sdo_applescript); | 4210 defsubr (&Sdo_applescript); |
3252 defsubr (&Smac_file_name_to_posix); | 4211 defsubr (&Smac_file_name_to_posix); |
3253 defsubr (&Sposix_file_name_to_mac); | 4212 defsubr (&Sposix_file_name_to_mac); |