remove README.Protocol and add a README that refers to the "real"
[fg:toms-fgdata.git] / Nasal / globals.nas
1 ##
2 # Returns true if the first object is an instance of the second
3 # (class) object.  Example: isa(someObject, props.Node)
4 #
5 isa = func {
6     obj = arg[0]; class = arg[1];
7     if(obj == nil or !contains(obj, "parents")) { return 0; }
8     foreach(c; obj.parents) {
9         if(c == class)     { return 1; }
10         elsif(isa(obj, c)) { return 1; }
11     }
12     return 0;
13 }
14
15 ##
16 # Invokes a FlightGear command specified by the first argument.  The
17 # second argument specifies the property tree to be passed to the
18 # command as its argument.  It may be either a props.Node object or a
19 # string, in which case it specifies a path in the global property
20 # tree.
21 #
22 fgcommand = func(cmd, node=nil) {
23     if(isa(node, props.Node)) node = node._g;
24     _fgcommand(cmd, node);
25 }
26
27 ##
28 # Returns the SGPropertyNode argument to the currently executing
29 # function. Wrapper for the internal _cmdarg function that retrieves
30 # the ghost handle to the argument and wraps it in a
31 # props.Node object.
32 #
33 cmdarg = func { props.wrapNode(_cmdarg()) }
34
35 ##
36 # Utility.  Does what it you think it does.
37 #
38 abs = func { if(arg[0] < 0) { -arg[0] } else { arg[0] } }
39
40 ##
41 # Convenience wrapper for the _interpolate function.  Takes a
42 # single string or props.Node object in arg[0] indicating a target
43 # property, and a variable-length list of time/value pairs.  Example:
44 #
45 #  interpolate("/animations/radar/angle",
46 #              180, 1, 360, 1, 0, 0,
47 #              180, 1, 360, 1, 0, 0,
48 #              180, 1, 360, 1, 0, 0,
49 #              180, 1, 360, 1, 0, 0,
50 #              180, 1, 360, 1, 0, 0,
51 #              180, 1, 360, 1, 0, 0,
52 #              180, 1, 360, 1, 0, 0,
53 #              180, 1, 360, 1, 0, 0);
54 #
55 # This will swing the "radar dish" smoothly through 8 revolutions over
56 # 16 seconds.  Note the use of zero-time interpolation between 360 and
57 # 0 to wrap the interpolated value properly.
58 #
59 interpolate = func {
60     if(isa(arg[0], props.Node)) { arg[0] = arg[0]._g; }
61     elsif(typeof(arg[0]) != "scalar") { return; }
62     _interpolate(arg[0], size(arg) == 1 ? [] : subvec(arg, 1));
63 }
64
65
66 ##
67 # Convenience wrapper for the _setlistener function. Takes a
68 # single string or props.Node object in arg[0] indicating the
69 # listened to property, a function in arg[1], and an optional
70 # bool in arg[2], which triggers the function initially if true.
71 #
72 setlistener = func {
73     if(isa(arg[0], props.Node)) { arg[0] = arg[0]._g; }
74     var id = _setlistener(arg[0], arg[1], size(arg) > 2 ? arg[2] : 0);
75     if(__.log_level <= 2) {
76         var c = caller(1);
77         print(sprintf("setting listener #%d in %s, line %s", id, c[2], c[3]))
78     }
79     return id;
80 }
81
82
83 ##
84 # Returns true if the symbol name is defined in the caller, or the
85 # caller's lexical namespace.  (i.e. defined("varname") tells you if
86 # you can use varname in an expression without a undefined symbol
87 # error.
88 #
89 defined = func(sym) {
90     var fn = 1;
91     while((var frame = caller(fn)) != nil) {
92         if(contains(frame[0], sym)) { return 1; }
93         fn += 1;
94     }
95     return 0;
96 }
97
98
99 ##
100 # Print log messages in appropriate --log-level.
101 # Usage: printlog("warn", "...");
102 # The underscore hash prevents helper functions/variables from
103 # needlessly polluting the global namespace.
104 #
105 __ = {};
106 __.dbg_types = { none:0, bulk:1, debug:2, info:3, warn:4, alert:5 };
107 __.log_level = __.dbg_types[getprop("/sim/logging/priority")];
108 printlog = func(level, args...) {
109     if(__.dbg_types[level] >= __.log_level) { call(print, args); }
110 }
111
112