2
# ###################################################################
3
# TclAE - Functions for building AppleEvents
4
# (modernization of appleEvents.tcl)
7
# created: 12/13/99 {12:55:28 PM}
8
# last update: 4/7/03 {11:37:39 PM}
10
# Author: Jonathan Guyer
11
# E-mail: jguyer@his.com
14
# www: http://www.his.com/jguyer/
16
# ========================================================================
17
# Copyright (c) 1999-2003 Jonathan Guyer
19
# ========================================================================
20
# Permission to use, copy, modify, and distribute this software and its
21
# documentation for any purpose and without fee is hereby granted,
22
# provided that the above copyright notice appear in all copies and that
23
# both that the copyright notice and warranty disclaimer appear in
24
# supporting documentation.
26
# Jonathan Guyer disclaims all warranties with regard to this software,
27
# including all implied warranties of merchantability and fitness. In
28
# no event shall Jonathan Guyer be liable for any special, indirect or
29
# consequential damages or any damages whatsoever resulting from loss of
30
# use, data or profits, whether in an action of contract, negligence or
31
# other tortuous action, arising out of or in connection with the use or
32
# performance of this software.
33
# ========================================================================
38
# modified by rev reason
39
# ---------- --- --- -----------
40
# 1999-12-13 JEG 1.0 original
41
# ###################################################################
44
# ◊◊◊◊ Initialization ◊◊◊◊ #
46
namespace eval tclAE::build {}
48
# ◊◊◊◊ Event handling ◊◊◊◊ #
51
# -------------------------------------------------------------------------
53
# "tclAE::build::throw" --
55
# Shorthand routine to check for AppleEvent errors
56
# -------------------------------------------------------------------------
58
proc tclAE::build::throw {args} {
59
# Event is only parsed for error checking, so purge
60
# when done (in the event of an error, it'll already
62
tclAE::disposeDesc [eval tclAE::build::event $args]
66
# -------------------------------------------------------------------------
68
# "tclAE::build::event" --
70
# Encapsulation for new and old style event building.
73
# The parsed result of the event.
74
# -------------------------------------------------------------------------
76
proc tclAE::build::event {args} {
77
set event [eval tclAE::send -r $args]
79
# No error if these keywords are missing
80
if {[catch {tclAE::getKeyData $event "errn" "long"} errn]} {
84
if {[catch {tclAE::getKeyData $event "errs" "TEXT"} errs]} {
88
error::throwOSErr $errn $errs
94
# -------------------------------------------------------------------------
96
# "tclAE::build::resultDataAs" --
98
# Shorthand routine to get the direct object result of an AEBuild call
99
# -------------------------------------------------------------------------
101
proc tclAE::build::resultDataAs {type args} {
106
set event [eval tclAE::build::event $args]
108
if {[catch {set result [tclAE::getKeyData $event ---- $type]} errorMsg]} {
109
if {![string match "Missing keyword '*' in record" $errorMsg]} {
110
# No direct object is OK
115
tclAE::disposeDesc $event
121
# -------------------------------------------------------------------------
123
# "tclAE::build::resultData" --
125
# Shorthand routine to get the direct object result of an AEBuild call
126
# -------------------------------------------------------------------------
128
proc tclAE::build::resultData {args} {
129
return [eval tclAE::build::resultDataAs **** $args]
133
# -------------------------------------------------------------------------
135
# "tclAE::build::resultDescAs" --
137
# Shorthand routine to get the direct object result of an AEBuild call,
139
# -------------------------------------------------------------------------
141
proc tclAE::build::resultDescAs {type args} {
146
set event [eval tclAE::build::event $args]
148
if {[catch {set result [tclAE::getKeyDesc $event ---- $type]} errorMsg]} {
149
if {![string match "Missing keyword '*' in record" $errorMsg]} {
150
# No direct object is OK
155
tclAE::disposeDesc $event
161
# -------------------------------------------------------------------------
163
# "tclAE::build::resultDesc" --
165
# Shorthand routine to get the direct object result of an AEBuild call,
166
# retaining the type code
167
# -------------------------------------------------------------------------
169
proc tclAE::build::resultDesc {args} {
170
return [eval tclAE::build::resultDescAs **** $args]
174
# -------------------------------------------------------------------------
176
# "tclAE::build::protect" --
178
# Alpha seems pickier about ident lengths than AEGizmos says it should be.
179
# Protect any whitespace.
182
# Returns $value, possible bracketed with ' quotes
186
# -------------------------------------------------------------------------
188
proc tclAE::build::protect {value} {
189
set value [string trimright $value]
190
if {[regexp {[][ @‘'“”:,({})-]} $value blah]} {
196
set value [format "%-4.4s" $value]
199
set value "'${value}'"
205
proc tclAE::build::objectProperty {process property object} {
206
return [tclAE::build::resultData $process core getd ---- \
207
[tclAE::build::propertyObject $property $object]]
210
# ◊◊◊◊ Builders ◊◊◊◊ #
212
proc tclAE::build::coercion {fromValue toType} {
213
set toType [tclAE::build::protect $toType]
215
switch -- [string index $fromValue 0] {
216
"\{" { # value is record
217
return "${toType}${fromValue}"
219
"\[" { # value is list
220
set msg "Cannot coerce a list"
221
error $msg "" [list AEParse 16 $msg]
224
return "${toType}(${fromValue})"
230
# -------------------------------------------------------------------------
232
# "tclAE::build::List" --
234
# Convert list 'l' to an AE list, i.e., "[l1, l2, l3, ...]".
235
# "-as type" coerces elements to 'type' before joining.
236
# Set "-untyped" if the elements do not consist of AEDescriptors
237
# -------------------------------------------------------------------------
239
proc tclAE::build::List {l args} {
244
if {[string length $opts(-as)] != 0} {
247
lappend out [tclAE::build::$opts(-as) $item]
249
} elseif {!$opts(-untyped)} {
258
set out [join $out ", "]
263
# -------------------------------------------------------------------------
265
# "tclAE::build::hexd" --
267
# Convert 'value' to '«value»'.
268
# value's spaces are stripped and it is left-padded with 0 to even digits.
269
# -------------------------------------------------------------------------
271
proc tclAE::build::hexd {value} {
273
if {[string length $newval] % 2} {
274
# left pad with zero to make even number of digits
275
set newval "0${newval}"
277
if {![is::Hexadecimal $newval]} {
278
if {[is::Whitespace $newval]} {
281
set msg "Non-hex-digit in \u00ab${value}\u00bb"
282
error $msg "" [list AECoerce 6 $msg]
285
return "\u00ab${newval}\u00bb"
290
# -------------------------------------------------------------------------
292
# "tclAE::build::bool" --
294
# Convert 'val' to AE 'bool(«val»)'.
295
# -------------------------------------------------------------------------
297
proc tclAE::build::bool {val} {
304
return [tclAE::build::coercion [tclAE::build::hexd $val] bool]
308
# -------------------------------------------------------------------------
310
# "tclAE::build::TEXT" --
312
# Convert $txt to “TEXT”.
313
# If there are curly quotes in $txt, output in raw hex, coerced to TEXT
314
# -------------------------------------------------------------------------
316
proc tclAE::build::TEXT {txt} {
318
return "[tclAE::build::coercion {} TEXT]"
320
if {[regexp {[\u0000-\u001f\u201c\u201d]} $txt]} {
321
binary scan $txt H* hexd
322
return "[tclAE::build::coercion [tclAE::build::hexd $hexd] TEXT]"
324
return "\u201c${txt}\u201d"
328
# -------------------------------------------------------------------------
330
# "tclAE::build::alis" --
332
# Convert 'path' to an alis(«...»).
333
# -------------------------------------------------------------------------
335
proc tclAE::build::alis {path} {
336
return [tclAE::coerceData TEXT $path alis]
340
# -------------------------------------------------------------------------
342
# "tclAE::build::fss" --
344
# Convert 'path' to an 'fss '(«...»).
345
# -------------------------------------------------------------------------
347
proc tclAE::build::fss {path} {
348
return [tclAE::coerceData TEXT $path fss]
352
# -------------------------------------------------------------------------
354
# "tclAE::build::path" --
356
# Convert 'path' to an alis(«...») or a furl(“...”), depending on OS.
357
# -------------------------------------------------------------------------
359
proc tclAE::build::path {path} {
362
# For some inexplicable reason, Apple decided that aliases
363
# cannot refer to non-existent files on Mac OS X, so
364
# we create a CFURL instead
365
if {$tcl_platform(platform) == "unix" && $tcl_platform(os) == "Darwin"} {
366
return "furl([tclAE::build::TEXT $path])"
368
return [tclAE::coerceData TEXT $path alis]
373
# -------------------------------------------------------------------------
375
# "tclAE::build::ident" --
377
# Dummy proc for rebuilding AEGizmos strings from parsed lists
378
# -------------------------------------------------------------------------
380
proc tclAE::build::enum {enum} {
381
return [tclAE::build::protect $enum]
385
proc tclAE::build::name {name} {
386
return "form:'name', seld:[tclAE::build::TEXT $name]"
389
proc tclAE::build::filename {name} {
391
if {$tcl_platform(platform) == "unix" && $tcl_platform(os) == "Darwin"} {
392
set name [tclAE::getHFSPath $name]
394
return "obj{want:type('file'), from:'null'(), [tclAE::build::name $name] } "
397
proc tclAE::build::winByName {name} {
398
return "obj{want:type('cwin'), from:'null'(), [tclAE::build::name $name]}"
401
proc tclAE::build::winByPos {absPos} {
402
return "obj{want:type('cwin'), from:'null'(), [tclAE::build::absPos $absPos]}"
405
proc tclAE::build::lineRange {absPos1 absPos2} {
406
set lineObj1 "obj{want:type('clin'), from:'ccnt'(), [tclAE::build::absPos $absPos1]}"
407
set lineObj2 "obj{want:type('clin'), from:'ccnt'(), [tclAE::build::absPos $absPos2]}"
408
return "form:'rang', seld:rang{star:$lineObj1, stop:$lineObj2}"
411
proc tclAE::build::charRange {absPos1 absPos2} {
412
set charObj1 "obj{want:type('cha '), from:'ccnt'(), [tclAE::build::absPos $absPos1]}"
413
set charObj2 "obj{want:type('cha '), from:'ccnt'(), [tclAE::build::absPos $absPos2]}"
414
return "form:'rang', seld:rang{star:$charObj1, stop:$charObj2}"
417
proc tclAE::build::absPos {posName} {
419
# Use '1' or 'first' to specify first position
420
# and '-1' or 'last' to specify last position.
422
if {$posName == "first"} {
424
} elseif {$posName == "last"} {
427
if {[is::Integer $posName]} {
428
return "form:indx, seld:long($posName)"
430
error "tclAE::build::absPos: bad argument"
434
proc tclAE::build::nullObject {} {
438
proc tclAE::build::objectType {type} {
442
proc tclAE::build::nameObject {type name {from ""}} {
444
set from [tclAE::build::nullObject]
448
want:[tclAE::build::objectType $type], \
454
proc tclAE::build::indexObject {type ind {from ""}} {
456
set from [tclAE::build::nullObject]
460
want:[tclAE::build::objectType $type], \
466
proc tclAE::build::everyObject {type {from ""}} {
467
return [tclAE::build::indexObject $type "abso('all ')" $from]
470
proc tclAE::build::rangeObject {type absPos1 absPos2 {from ""}} {
472
set from [tclAE::build::nullObject]
474
set type [tclAE::build::objectType $type]
479
[tclAE::build::absPos $absPos1] \
484
[tclAE::build::absPos $absPos2] \
497
proc tclAE::build::propertyObject {prop {object ""}} {
498
if {[string length $object] == 0} {
499
set object [tclAE::build::nullObject]
504
want:[tclAE::build::objectType prop], \
505
seld:[tclAE::build::objectType $prop], \
510
proc tclAE::build::propertyListObject {props {object ""}} {
511
if {[string length $object] == 0} {
512
set object [tclAE::build::nullObject]
517
want:[tclAE::build::objectType prop], \
518
seld:[tclAE::build::List $props -as objectType], \
523
# ◊◊◊◊ Utilities ◊◊◊◊ #
526
# -------------------------------------------------------------------------
528
# "tclAE::build::startupDisk" --
530
# The name of the Startup Disk (as sometimes returned by the Finder)
531
# -------------------------------------------------------------------------
533
proc tclAE::build::startupDisk {} {
534
return [tclAE::build::objectProperty 'MACS' pnam \
535
"obj \{want:type(prop), from:'null'(), \
536
form:prop, seld:type(sdsk)\}" \
541
# -------------------------------------------------------------------------
543
# "tclAE::build::userName" --
545
# Return the default user name. The Mac's owner name,
546
# which is in String Resource ID -16096, is inaccesible to Tcl
547
# (at least until Tcl 8 is implemented).
549
# Try different mechanisms for determining the user name.
551
# -------------------------------------------------------------------------
553
if {([info exists alpha::platform] && ${alpha::platform} != "alpha") ||
554
($tcl_platform(platform) == "unix" && $tcl_platform(os) == "Darwin")} {
555
;proc tclAE::build::userName {} {
558
# better to use tcl_platform(user)?
562
;proc tclAE::build::userName {} {
563
return [text::fromPstring [resource read "STR " -16096]]
567
# Build a Folder object from its name
568
proc tclAE::build::foldername {name} {
570
if {$tcl_platform(platform) == "unix" && $tcl_platform(os) == "Darwin"} {
571
set name [tclAE::getHFSPath $name]
573
return "obj{want:type('cfol'), from:'null'(), [tclAE::build::name $name] } "
576
# ###################################################################
577
# TclAE - Functions for building AppleEvents
578
# (modernization of appleEvents.tcl)
580
# FILE: "aebuild.tcl"
581
# created: 12/13/99 {12:55:28 PM}
582
# last update: 4/7/03 {11:37:39 PM}
584
# Author: Jonathan Guyer
585
# E-mail: jguyer@his.com
588
# www: http://www.his.com/jguyer/
590
# ========================================================================
591
# Copyright (c) 1999-2003 Jonathan Guyer
592
# All rights reserved
593
# ========================================================================
594
# Permission to use, copy, modify, and distribute this software and its
595
# documentation for any purpose and without fee is hereby granted,
596
# provided that the above copyright notice appear in all copies and that
597
# both that the copyright notice and warranty disclaimer appear in
598
# supporting documentation.
600
# Jonathan Guyer disclaims all warranties with regard to this software,
601
# including all implied warranties of merchantability and fitness. In
602
# no event shall Jonathan Guyer be liable for any special, indirect or
603
# consequential damages or any damages whatsoever resulting from loss of
604
# use, data or profits, whether in an action of contract, negligence or
605
# other tortuous action, arising out of or in connection with the use or
606
# performance of this software.
607
# ========================================================================
612
# modified by rev reason
613
# ---------- --- --- -----------
614
# 1999-12-13 JEG 1.0 original
615
# ###################################################################
618
# ◊◊◊◊ Initialization ◊◊◊◊ #
620
namespace eval tclAE::build {}
622
# ◊◊◊◊ Event handling ◊◊◊◊ #
625
# -------------------------------------------------------------------------
627
# "tclAE::build::throw" --
629
# Shorthand routine to check for AppleEvent errors
630
# -------------------------------------------------------------------------
632
proc tclAE::build::throw {args} {
633
# Event is only parsed for error checking, so purge
634
# when done (in the event of an error, it'll already
636
tclAE::disposeDesc [eval tclAE::build::event $args]
640
# -------------------------------------------------------------------------
642
# "tclAE::build::event" --
644
# Encapsulation for new and old style event building.
647
# The parsed result of the event.
648
# -------------------------------------------------------------------------
650
proc tclAE::build::event {args} {
651
set event [eval tclAE::send -r $args]
653
# No error if these keywords are missing
654
if {[catch {tclAE::getKeyData $event "errn" "long"} errn]} {
658
if {[catch {tclAE::getKeyData $event "errs" "TEXT"} errs]} {
662
error::throwOSErr $errn $errs
668
# -------------------------------------------------------------------------
670
# "tclAE::build::resultDataAs" --
672
# Shorthand routine to get the direct object result of an AEBuild call
673
# -------------------------------------------------------------------------
675
proc tclAE::build::resultDataAs {type args} {
680
set event [eval tclAE::build::event $args]
682
if {[catch {set result [tclAE::getKeyData $event ---- $type]} errorMsg]} {
683
if {![string match "Missing keyword '*' in record" $errorMsg]} {
684
# No direct object is OK
689
tclAE::disposeDesc $event
695
# -------------------------------------------------------------------------
697
# "tclAE::build::resultData" --
699
# Shorthand routine to get the direct object result of an AEBuild call
700
# -------------------------------------------------------------------------
702
proc tclAE::build::resultData {args} {
703
return [eval tclAE::build::resultDataAs **** $args]
707
# -------------------------------------------------------------------------
709
# "tclAE::build::resultDescAs" --
711
# Shorthand routine to get the direct object result of an AEBuild call,
713
# -------------------------------------------------------------------------
715
proc tclAE::build::resultDescAs {type args} {
720
set event [eval tclAE::build::event $args]
722
if {[catch {set result [tclAE::getKeyDesc $event ---- $type]} errorMsg]} {
723
if {![string match "Missing keyword '*' in record" $errorMsg]} {
724
# No direct object is OK
729
tclAE::disposeDesc $event
735
# -------------------------------------------------------------------------
737
# "tclAE::build::resultDesc" --
739
# Shorthand routine to get the direct object result of an AEBuild call,
740
# retaining the type code
741
# -------------------------------------------------------------------------
743
proc tclAE::build::resultDesc {args} {
744
return [eval tclAE::build::resultDescAs **** $args]
748
# -------------------------------------------------------------------------
750
# "tclAE::build::protect" --
752
# Alpha seems pickier about ident lengths than AEGizmos says it should be.
753
# Protect any whitespace.
756
# Returns $value, possible bracketed with ' quotes
760
# -------------------------------------------------------------------------
762
proc tclAE::build::protect {value} {
763
set value [string trimright $value]
764
if {[regexp {[][ @‘'“”:,({})-]} $value blah]} {
770
set value [format "%-4.4s" $value]
773
set value "'${value}'"
779
proc tclAE::build::objectProperty {process property object} {
780
return [tclAE::build::resultData $process core getd ---- \
781
[tclAE::build::propertyObject $property $object]]
784
# ◊◊◊◊ Builders ◊◊◊◊ #
786
proc tclAE::build::coercion {fromValue toType} {
787
set toType [tclAE::build::protect $toType]
789
switch -- [string index $fromValue 0] {
790
"\{" { # value is record
791
return "${toType}${fromValue}"
793
"\[" { # value is list
794
set msg "Cannot coerce a list"
795
error $msg "" [list AEParse 16 $msg]
798
return "${toType}(${fromValue})"
804
# -------------------------------------------------------------------------
806
# "tclAE::build::List" --
808
# Convert list 'l' to an AE list, i.e., "[l1, l2, l3, ...]".
809
# "-as type" coerces elements to 'type' before joining.
810
# Set "-untyped" if the elements do not consist of AEDescriptors
811
# -------------------------------------------------------------------------
813
proc tclAE::build::List {l args} {
818
if {[string length $opts(-as)] != 0} {
821
lappend out [tclAE::build::$opts(-as) $item]
823
} elseif {!$opts(-untyped)} {
832
set out [join $out ", "]
837
# -------------------------------------------------------------------------
839
# "tclAE::build::hexd" --
841
# Convert 'value' to '«value»'.
842
# value's spaces are stripped and it is left-padded with 0 to even digits.
843
# -------------------------------------------------------------------------
845
proc tclAE::build::hexd {value} {
847
if {[string length $newval] % 2} {
848
# left pad with zero to make even number of digits
849
set newval "0${newval}"
851
if {![is::Hexadecimal $newval]} {
852
if {[is::Whitespace $newval]} {
855
set msg "Non-hex-digit in \u00ab${value}\u00bb"
856
error $msg "" [list AECoerce 6 $msg]
859
return "\u00ab${newval}\u00bb"
864
# -------------------------------------------------------------------------
866
# "tclAE::build::bool" --
868
# Convert 'val' to AE 'bool(«val»)'.
869
# -------------------------------------------------------------------------
871
proc tclAE::build::bool {val} {
878
return [tclAE::build::coercion [tclAE::build::hexd $val] bool]
882
# -------------------------------------------------------------------------
884
# "tclAE::build::TEXT" --
886
# Convert $txt to “TEXT”.
887
# If there are curly quotes in $txt, output in raw hex, coerced to TEXT
888
# -------------------------------------------------------------------------
890
proc tclAE::build::TEXT {txt} {
892
return "[tclAE::build::coercion {} TEXT]"
894
if {[regexp {[\u0000-\u001f\u201c\u201d]} $txt]} {
895
binary scan $txt H* hexd
896
return "[tclAE::build::coercion [tclAE::build::hexd $hexd] TEXT]"
898
return "\u201c${txt}\u201d"
902
# -------------------------------------------------------------------------
904
# "tclAE::build::alis" --
906
# Convert 'path' to an alis(«...»).
907
# -------------------------------------------------------------------------
909
proc tclAE::build::alis {path} {
910
return [tclAE::coerceData TEXT $path alis]
914
# -------------------------------------------------------------------------
916
# "tclAE::build::fss" --
918
# Convert 'path' to an 'fss '(«...»).
919
# -------------------------------------------------------------------------
921
proc tclAE::build::fss {path} {
922
return [tclAE::coerceData TEXT $path fss]
926
# -------------------------------------------------------------------------
928
# "tclAE::build::path" --
930
# Convert 'path' to an alis(«...») or a furl(“...”), depending on OS.
931
# -------------------------------------------------------------------------
933
proc tclAE::build::path {path} {
936
# For some inexplicable reason, Apple decided that aliases
937
# cannot refer to non-existent files on Mac OS X, so
938
# we create a CFURL instead
939
if {$tcl_platform(platform) == "unix" && $tcl_platform(os) == "Darwin"} {
940
return "furl([tclAE::build::TEXT $path])"
942
return [tclAE::coerceData TEXT $path alis]
947
# -------------------------------------------------------------------------
949
# "tclAE::build::ident" --
951
# Dummy proc for rebuilding AEGizmos strings from parsed lists
952
# -------------------------------------------------------------------------
954
proc tclAE::build::enum {enum} {
955
return [tclAE::build::protect $enum]
959
proc tclAE::build::name {name} {
960
return "form:'name', seld:[tclAE::build::TEXT $name]"
963
proc tclAE::build::filename {name} {
965
if {$tcl_platform(platform) == "unix" && $tcl_platform(os) == "Darwin"} {
966
set name [tclAE::getHFSPath $name]
968
return "obj{want:type('file'), from:'null'(), [tclAE::build::name $name] } "
971
proc tclAE::build::winByName {name} {
972
return "obj{want:type('cwin'), from:'null'(), [tclAE::build::name $name]}"
975
proc tclAE::build::winByPos {absPos} {
976
return "obj{want:type('cwin'), from:'null'(), [tclAE::build::absPos $absPos]}"
979
proc tclAE::build::lineRange {absPos1 absPos2} {
980
set lineObj1 "obj{want:type('clin'), from:'ccnt'(), [tclAE::build::absPos $absPos1]}"
981
set lineObj2 "obj{want:type('clin'), from:'ccnt'(), [tclAE::build::absPos $absPos2]}"
982
return "form:'rang', seld:rang{star:$lineObj1, stop:$lineObj2}"
985
proc tclAE::build::charRange {absPos1 absPos2} {
986
set charObj1 "obj{want:type('cha '), from:'ccnt'(), [tclAE::build::absPos $absPos1]}"
987
set charObj2 "obj{want:type('cha '), from:'ccnt'(), [tclAE::build::absPos $absPos2]}"
988
return "form:'rang', seld:rang{star:$charObj1, stop:$charObj2}"
991
proc tclAE::build::absPos {posName} {
993
# Use '1' or 'first' to specify first position
994
# and '-1' or 'last' to specify last position.
996
if {$posName == "first"} {
998
} elseif {$posName == "last"} {
1001
if {[is::Integer $posName]} {
1002
return "form:indx, seld:long($posName)"
1004
error "tclAE::build::absPos: bad argument"
1008
proc tclAE::build::nullObject {} {
1012
proc tclAE::build::objectType {type} {
1013
return "type($type)"
1016
proc tclAE::build::nameObject {type name {from ""}} {
1018
set from [tclAE::build::nullObject]
1022
want:[tclAE::build::objectType $type], \
1028
proc tclAE::build::indexObject {type ind {from ""}} {
1030
set from [tclAE::build::nullObject]
1034
want:[tclAE::build::objectType $type], \
1040
proc tclAE::build::everyObject {type {from ""}} {
1041
return [tclAE::build::indexObject $type "abso('all ')" $from]
1044
proc tclAE::build::rangeObject {type absPos1 absPos2 {from ""}} {
1046
set from [tclAE::build::nullObject]
1048
set type [tclAE::build::objectType $type]
1053
[tclAE::build::absPos $absPos1] \
1058
[tclAE::build::absPos $absPos2] \
1071
proc tclAE::build::propertyObject {prop {object ""}} {
1072
if {[string length $object] == 0} {
1073
set object [tclAE::build::nullObject]
1078
want:[tclAE::build::objectType prop], \
1079
seld:[tclAE::build::objectType $prop], \
1084
proc tclAE::build::propertyListObject {props {object ""}} {
1085
if {[string length $object] == 0} {
1086
set object [tclAE::build::nullObject]
1091
want:[tclAE::build::objectType prop], \
1092
seld:[tclAE::build::List $props -as objectType], \
1097
# ◊◊◊◊ Utilities ◊◊◊◊ #
1100
# -------------------------------------------------------------------------
1102
# "tclAE::build::startupDisk" --
1104
# The name of the Startup Disk (as sometimes returned by the Finder)
1105
# -------------------------------------------------------------------------
1107
proc tclAE::build::startupDisk {} {
1108
return [tclAE::build::objectProperty 'MACS' pnam \
1109
"obj \{want:type(prop), from:'null'(), \
1110
form:prop, seld:type(sdsk)\}" \
1115
# -------------------------------------------------------------------------
1117
# "tclAE::build::userName" --
1119
# Return the default user name. The Mac's owner name,
1120
# which is in String Resource ID -16096, is inaccesible to Tcl
1121
# (at least until Tcl 8 is implemented).
1123
# Try different mechanisms for determining the user name.
1125
# -------------------------------------------------------------------------
1127
if {([info exists alpha::platform] && ${alpha::platform} != "alpha") ||
1128
($tcl_platform(platform) == "unix" && $tcl_platform(os) == "Darwin")} {
1129
;proc tclAE::build::userName {} {
1132
# better to use tcl_platform(user)?
1136
;proc tclAE::build::userName {} {
1137
return [text::fromPstring [resource read "STR " -16096]]
1141
# Build a Folder object from its name
1142
proc tclAE::build::foldername {name} {
1144
if {$tcl_platform(platform) == "unix" && $tcl_platform(os) == "Darwin"} {
1145
set name [tclAE::getHFSPath $name]
1147
return "obj{want:type('cfol'), from:'null'(), [tclAE::build::name $name] } "
1150
# ###################################################################
1151
# TclAE - Functions for building AppleEvents
1152
# (modernization of appleEvents.tcl)
1154
# FILE: "aebuild.tcl"
1155
# created: 12/13/99 {12:55:28 PM}
1156
# last update: 4/7/03 {11:37:39 PM}
1158
# Author: Jonathan Guyer
1159
# E-mail: jguyer@his.com
1161
# POMODORO no seisan
1162
# www: http://www.his.com/jguyer/
1164
# ========================================================================
1165
# Copyright (c) 1999-2003 Jonathan Guyer
1166
# All rights reserved
1167
# ========================================================================
1168
# Permission to use, copy, modify, and distribute this software and its
1169
# documentation for any purpose and without fee is hereby granted,
1170
# provided that the above copyright notice appear in all copies and that
1171
# both that the copyright notice and warranty disclaimer appear in
1172
# supporting documentation.
1174
# Jonathan Guyer disclaims all warranties with regard to this software,
1175
# including all implied warranties of merchantability and fitness. In
1176
# no event shall Jonathan Guyer be liable for any special, indirect or
1177
# consequential damages or any damages whatsoever resulting from loss of
1178
# use, data or profits, whether in an action of contract, negligence or
1179
# other tortuous action, arising out of or in connection with the use or
1180
# performance of this software.
1181
# ========================================================================
1186
# modified by rev reason
1187
# ---------- --- --- -----------
1188
# 1999-12-13 JEG 1.0 original
1189
# ###################################################################
1192
# ◊◊◊◊ Initialization ◊◊◊◊ #
1194
namespace eval tclAE::build {}
1196
# ◊◊◊◊ Event handling ◊◊◊◊ #
1199
# -------------------------------------------------------------------------
1201
# "tclAE::build::throw" --
1203
# Shorthand routine to check for AppleEvent errors
1204
# -------------------------------------------------------------------------
1206
proc tclAE::build::throw {args} {
1207
# Event is only parsed for error checking, so purge
1208
# when done (in the event of an error, it'll already
1210
tclAE::disposeDesc [eval tclAE::build::event $args]
1214
# -------------------------------------------------------------------------
1216
# "tclAE::build::event" --
1218
# Encapsulation for new and old style event building.
1221
# The parsed result of the event.
1222
# -------------------------------------------------------------------------
1224
proc tclAE::build::event {args} {
1225
set event [eval tclAE::send -r $args]
1227
# No error if these keywords are missing
1228
if {[catch {tclAE::getKeyData $event "errn" "long"} errn]} {
1232
if {[catch {tclAE::getKeyData $event "errs" "TEXT"} errs]} {
1236
error::throwOSErr $errn $errs
1242
# -------------------------------------------------------------------------
1244
# "tclAE::build::resultDataAs" --
1246
# Shorthand routine to get the direct object result of an AEBuild call
1247
# -------------------------------------------------------------------------
1249
proc tclAE::build::resultDataAs {type args} {
1254
set event [eval tclAE::build::event $args]
1256
if {[catch {set result [tclAE::getKeyData $event ---- $type]} errorMsg]} {
1257
if {![string match "Missing keyword '*' in record" $errorMsg]} {
1258
# No direct object is OK
1263
tclAE::disposeDesc $event
1269
# -------------------------------------------------------------------------
1271
# "tclAE::build::resultData" --
1273
# Shorthand routine to get the direct object result of an AEBuild call
1274
# -------------------------------------------------------------------------
1276
proc tclAE::build::resultData {args} {
1277
return [eval tclAE::build::resultDataAs **** $args]
1281
# -------------------------------------------------------------------------
1283
# "tclAE::build::resultDescAs" --
1285
# Shorthand routine to get the direct object result of an AEBuild call,
1287
# -------------------------------------------------------------------------
1289
proc tclAE::build::resultDescAs {type args} {
1294
set event [eval tclAE::build::event $args]
1296
if {[catch {set result [tclAE::getKeyDesc $event ---- $type]} errorMsg]} {
1297
if {![string match "Missing keyword '*' in record" $errorMsg]} {
1298
# No direct object is OK
1303
tclAE::disposeDesc $event
1309
# -------------------------------------------------------------------------
1311
# "tclAE::build::resultDesc" --
1313
# Shorthand routine to get the direct object result of an AEBuild call,
1314
# retaining the type code
1315
# -------------------------------------------------------------------------
1317
proc tclAE::build::resultDesc {args} {
1318
return [eval tclAE::build::resultDescAs **** $args]
1322
# -------------------------------------------------------------------------
1324
# "tclAE::build::protect" --
1326
# Alpha seems pickier about ident lengths than AEGizmos says it should be.
1327
# Protect any whitespace.
1330
# Returns $value, possible bracketed with ' quotes
1334
# -------------------------------------------------------------------------
1336
proc tclAE::build::protect {value} {
1337
set value [string trimright $value]
1338
if {[regexp {[][ @‘'“”:,({})-]} $value blah]} {
1344
set value [format "%-4.4s" $value]
1347
set value "'${value}'"
1353
proc tclAE::build::objectProperty {process property object} {
1354
return [tclAE::build::resultData $process core getd ---- \
1355
[tclAE::build::propertyObject $property $object]]
1358
# ◊◊◊◊ Builders ◊◊◊◊ #
1360
proc tclAE::build::coercion {fromValue toType} {
1361
set toType [tclAE::build::protect $toType]
1363
switch -- [string index $fromValue 0] {
1364
"\{" { # value is record
1365
return "${toType}${fromValue}"
1367
"\[" { # value is list
1368
set msg "Cannot coerce a list"
1369
error $msg "" [list AEParse 16 $msg]
1372
return "${toType}(${fromValue})"
1378
# -------------------------------------------------------------------------
1380
# "tclAE::build::List" --
1382
# Convert list 'l' to an AE list, i.e., "[l1, l2, l3, ...]".
1383
# "-as type" coerces elements to 'type' before joining.
1384
# Set "-untyped" if the elements do not consist of AEDescriptors
1385
# -------------------------------------------------------------------------
1387
proc tclAE::build::List {l args} {
1389
set opts(-untyped) 0
1392
if {[string length $opts(-as)] != 0} {
1395
lappend out [tclAE::build::$opts(-as) $item]
1397
} elseif {!$opts(-untyped)} {
1406
set out [join $out ", "]
1411
# -------------------------------------------------------------------------
1413
# "tclAE::build::hexd" --
1415
# Convert 'value' to '«value»'.
1416
# value's spaces are stripped and it is left-padded with 0 to even digits.
1417
# -------------------------------------------------------------------------
1419
proc tclAE::build::hexd {value} {
1421
if {[string length $newval] % 2} {
1422
# left pad with zero to make even number of digits
1423
set newval "0${newval}"
1425
if {![is::Hexadecimal $newval]} {
1426
if {[is::Whitespace $newval]} {
1429
set msg "Non-hex-digit in \u00ab${value}\u00bb"
1430
error $msg "" [list AECoerce 6 $msg]
1433
return "\u00ab${newval}\u00bb"
1438
# -------------------------------------------------------------------------
1440
# "tclAE::build::bool" --
1442
# Convert 'val' to AE 'bool(«val»)'.
1443
# -------------------------------------------------------------------------
1445
proc tclAE::build::bool {val} {
1452
return [tclAE::build::coercion [tclAE::build::hexd $val] bool]
1456
# -------------------------------------------------------------------------
1458
# "tclAE::build::TEXT" --
1460
# Convert $txt to “TEXT”.
1461
# If there are curly quotes in $txt, output in raw hex, coerced to TEXT
1462
# -------------------------------------------------------------------------
1464
proc tclAE::build::TEXT {txt} {
1466
return "[tclAE::build::coercion {} TEXT]"
1468
if {[regexp {[\u0000-\u001f\u201c\u201d]} $txt]} {
1469
binary scan $txt H* hexd
1470
return "[tclAE::build::coercion [tclAE::build::hexd $hexd] TEXT]"
1472
return "\u201c${txt}\u201d"
1476
# -------------------------------------------------------------------------
1478
# "tclAE::build::alis" --
1480
# Convert 'path' to an alis(«...»).
1481
# -------------------------------------------------------------------------
1483
proc tclAE::build::alis {path} {
1484
return [tclAE::coerceData TEXT $path alis]
1488
# -------------------------------------------------------------------------
1490
# "tclAE::build::fss" --
1492
# Convert 'path' to an 'fss '(«...»).
1493
# -------------------------------------------------------------------------
1495
proc tclAE::build::fss {path} {
1496
return [tclAE::coerceData TEXT $path fss]
1500
# -------------------------------------------------------------------------
1502
# "tclAE::build::path" --
1504
# Convert 'path' to an alis(«...») or a furl(“...”), depending on OS.
1505
# -------------------------------------------------------------------------
1507
proc tclAE::build::path {path} {
1510
# For some inexplicable reason, Apple decided that aliases
1511
# cannot refer to non-existent files on Mac OS X, so
1512
# we create a CFURL instead
1513
if {$tcl_platform(platform) == "unix" && $tcl_platform(os) == "Darwin"} {
1514
return "furl([tclAE::build::TEXT $path])"
1516
return [tclAE::coerceData TEXT $path alis]
1521
# -------------------------------------------------------------------------
1523
# "tclAE::build::ident" --
1525
# Dummy proc for rebuilding AEGizmos strings from parsed lists
1526
# -------------------------------------------------------------------------
1528
proc tclAE::build::enum {enum} {
1529
return [tclAE::build::protect $enum]
1533
proc tclAE::build::name {name} {
1534
return "form:'name', seld:[tclAE::build::TEXT $name]"
1537
proc tclAE::build::filename {name} {
1539
if {$tcl_platform(platform) == "unix" && $tcl_platform(os) == "Darwin"} {
1540
set name [tclAE::getHFSPath $name]
1542
return "obj{want:type('file'), from:'null'(), [tclAE::build::name $name] } "
1545
proc tclAE::build::winByName {name} {
1546
return "obj{want:type('cwin'), from:'null'(), [tclAE::build::name $name]}"
1549
proc tclAE::build::winByPos {absPos} {
1550
return "obj{want:type('cwin'), from:'null'(), [tclAE::build::absPos $absPos]}"
1553
proc tclAE::build::lineRange {absPos1 absPos2} {
1554
set lineObj1 "obj{want:type('clin'), from:'ccnt'(), [tclAE::build::absPos $absPos1]}"
1555
set lineObj2 "obj{want:type('clin'), from:'ccnt'(), [tclAE::build::absPos $absPos2]}"
1556
return "form:'rang', seld:rang{star:$lineObj1, stop:$lineObj2}"
1559
proc tclAE::build::charRange {absPos1 absPos2} {
1560
set charObj1 "obj{want:type('cha '), from:'ccnt'(), [tclAE::build::absPos $absPos1]}"
1561
set charObj2 "obj{want:type('cha '), from:'ccnt'(), [tclAE::build::absPos $absPos2]}"
1562
return "form:'rang', seld:rang{star:$charObj1, stop:$charObj2}"
1565
proc tclAE::build::absPos {posName} {
1567
# Use '1' or 'first' to specify first position
1568
# and '-1' or 'last' to specify last position.
1570
if {$posName == "first"} {
1572
} elseif {$posName == "last"} {
1575
if {[is::Integer $posName]} {
1576
return "form:indx, seld:long($posName)"
1578
error "tclAE::build::absPos: bad argument"
1582
proc tclAE::build::nullObject {} {
1586
proc tclAE::build::objectType {type} {
1587
return "type($type)"
1590
proc tclAE::build::nameObject {type name {from ""}} {
1592
set from [tclAE::build::nullObject]
1596
want:[tclAE::build::objectType $type], \
1602
proc tclAE::build::indexObject {type ind {from ""}} {
1604
set from [tclAE::build::nullObject]
1608
want:[tclAE::build::objectType $type], \
1614
proc tclAE::build::everyObject {type {from ""}} {
1615
return [tclAE::build::indexObject $type "abso('all ')" $from]
1618
proc tclAE::build::rangeObject {type absPos1 absPos2 {from ""}} {
1620
set from [tclAE::build::nullObject]
1622
set type [tclAE::build::objectType $type]
1627
[tclAE::build::absPos $absPos1] \
1632
[tclAE::build::absPos $absPos2] \
1645
proc tclAE::build::propertyObject {prop {object ""}} {
1646
if {[string length $object] == 0} {
1647
set object [tclAE::build::nullObject]
1652
want:[tclAE::build::objectType prop], \
1653
seld:[tclAE::build::objectType $prop], \
1658
proc tclAE::build::propertyListObject {props {object ""}} {
1659
if {[string length $object] == 0} {
1660
set object [tclAE::build::nullObject]
1665
want:[tclAE::build::objectType prop], \
1666
seld:[tclAE::build::List $props -as objectType], \
1671
# ◊◊◊◊ Utilities ◊◊◊◊ #
1674
# -------------------------------------------------------------------------
1676
# "tclAE::build::startupDisk" --
1678
# The name of the Startup Disk (as sometimes returned by the Finder)
1679
# -------------------------------------------------------------------------
1681
proc tclAE::build::startupDisk {} {
1682
return [tclAE::build::objectProperty 'MACS' pnam \
1683
"obj \{want:type(prop), from:'null'(), \
1684
form:prop, seld:type(sdsk)\}" \
1689
# -------------------------------------------------------------------------
1691
# "tclAE::build::userName" --
1693
# Return the default user name. The Mac's owner name,
1694
# which is in String Resource ID -16096, is inaccesible to Tcl
1695
# (at least until Tcl 8 is implemented).
1697
# Try different mechanisms for determining the user name.
1699
# -------------------------------------------------------------------------
1701
if {([info exists alpha::platform] && ${alpha::platform} != "alpha") ||
1702
($tcl_platform(platform) == "unix" && $tcl_platform(os) == "Darwin")} {
1703
;proc tclAE::build::userName {} {
1706
# better to use tcl_platform(user)?
1710
;proc tclAE::build::userName {} {
1711
return [text::fromPstring [resource read "STR " -16096]]
1715
# Build a Folder object from its name
1716
proc tclAE::build::foldername {name} {
1718
if {$tcl_platform(platform) == "unix" && $tcl_platform(os) == "Darwin"} {
1719
set name [tclAE::getHFSPath $name]
1721
return "obj{want:type('cfol'), from:'null'(), [tclAE::build::name $name] } "