This file is indexed.

/usr/share/tcltk/tklib0.6/diagrams/direction.tcl is in tklib 0.6-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
## -*- tcl -*-
## (C) 2010 Andreas Kupries <andreas_kupries@users.sourceforge.net>
## BSD Licensed
# # ## ### ##### ######## ############# ######################

#
# Database of named directions, for use in the diagram controller.
#
# Directions are identified by name and each has a set of attributes,
# each identified by name, with associated value. The attributes are
# not typed.
#
# Standard attributes are 'angle' and 'oppposite', the first providing
# the angle of the direction, in degrees (0-360, 0 == right/east, 90
# == up/north), and the second naming the complentary direction going
# into the opposite direction (+/- 180 degrees).
#
# The eight directions (octants) of the compass rose are predefined,
# standard.
#
# Beyond the directions the system also manages 'aliases',
# i.e. alternate/secondary names for the primary directions.
#
# All names are handled case-insensitive!
#

##
# # ## ### ##### ######## ############# ######################
## Requisites

package require Tcl 8.5 ; # Want the nice things it brings (dicts, {*}, etc.)
package require snit    ; # Object framework.

# # ## ### ##### ######## ############# ######################
## Implementation

snit::type ::diagram::direction {

    # # ## ### ##### ######## ############# ######################
    ## Public API :: Extending the database

    method {new direction} {name args} {
	set thename [string tolower $name]
	# Argument validation.
	if {[info exists myinfo($thename)] ||
	    [info exists myalias($thename)]} {
	    return -code error "direction already known"
	} elseif {[llength $args] % 2 == 1} {
	    return -code error "Expected a dictionary, got \"$args\""
	} elseif {![dict exists $args angle]} {
	    return -code error "Standard attribute 'angle' is missing"
	} elseif {![dict exists $args opposite]} {
	    return -code error "Standard attribute 'opposite' is missing"
	}
	# Note: Can't check the value of opposite, a direction, for
	# existence, because then we are unable to define the pairs.

	# Should either check the angle, or auto-reduce to the proper
	# interval.

	set myinfo($thename) $args
	return
    }

    method {new alias} {name primary} {
	set thename    [string tolower $name]
	set theprimary [string tolower $primary]
	# Argument validation.
	if {[info exists myalias($thename)]} {
	    return -code error "alias already known"
	} elseif {![info exists myalias($theprimary)] &&
		  ![info exists myinfo($theprimary)]} {
	    return -code error "existing direction expected, not known"
	}
	# (*a) Resolve alias to alias in favor of the underlying
	# primary => Short lookup, no iteration required.
	if {[info exists myalias($theprimary)]} {
	    set theprimary $myalias($theprimary)
	}
	# And remember the mapping.
	set mydb($thename) $theprimary
	return
    }

    # # ## ### ##### ######## ############# ######################
    ## Public API :: Validate directions, either as explict angle, or named.
    ##               and return it normalized (angle reduced to
    ##               interval, primary name of any alias).

    method validate {direction} {
	if {[Norm $direction angle]} { return $angle }
	set d $direction
	# Only one alias lookup necessary, see (*a) in 'new alias'.
	if {[info exists myalias($d)]} { set d $myalias($d) }
	if {[info exists myinfo($d)]}  { return $d }
	return -code error "Expected direction, got \"$direction\""
    }

    method is {d} {
	if {[Norm $d angle]} { return 1 }
	# Only one alias lookup necessary, see (*a) in 'new alias'.
	if {[info exists myalias($d)]} { set d $myalias($d) }
	return [info exists myinfo($d)]
    }

    method isStrict {d} {
	# Only one alias lookup necessary, see (*a) in 'new alias'.
	if {[info exists myalias($d)]} { set d $myalias($d) }
	return [info exists myinfo($d)]
    }

    method map {corners c} {
	if {[dict exists $corners $c]} {
	    return $c
	} elseif {[$self is $c]} {
	    set new [$self validate $c]
	    if {$new ne $c} {
		return $new
	    }
	}

	# Find nearest corner by angle.
	set angle [$self get $c angle]
	set delta Inf
	set min {}
	foreach d [dict keys $corners] {
	    if {![$self isStrict $d]} continue
	    if {[catch {
		set da [$self get $d angle]
	    }]} continue
	    set dda [expr {abs($da - $angle)}]
	    if {$dda >= $delta} continue
	    set delta $dda
	    set min   $d
	}
	if {$min ne $c} {
	    return $min
	}
	return $c
    }

    # # ## ### ##### ######## ############# ######################
    ## Public API :: Retrieve directional attributes (all, or
    ##               specific). Accepts angles as well, and uses
    ##               nearest named direction.

    method get {direction {detail {}}} {
	if {[Norm $direction angle]} {
	    set d [$self FindByAngle $angle]
	} elseif {[info exists myalias($direction)]} {
	    set d $myalias($direction)
	} else {
	    set d $direction
	}
	if {[info exists myinfo($d)]}  {
	    if {[llength [info level 0]] == 7} {
		return [dict get $myinfo($d) $detail]
	    } else {
		return $myinfo($d)
	    }
	}
	return -code error "Expected direction, got \"$direction\""
    }

    # # ## ### ##### ######## ############# ######################

    proc Norm {angle varname} {
	if {![string is double -strict $angle]} { return 0 }
	while {$angle < 0}   { set angle [expr {$angle + 360}] }
	while {$angle > 360} { set angle [expr {$angle - 360}] }
	upvar 1 $varname normalized
	set normalized $angle
	return 1
    }

    method FindByAngle {angle} {
	# Find nearest named angle.
	set name {}
	set delta 720
	foreach k [array names myinfo] {
	    if {![dict exists $myinfo($k) angle]} continue
	    set a [dict get $myinfo($k) angle]
	    if {$a eq {}} continue
	    set d [expr {abs($a-$angle)}]
	    if {$d < $delta} {
		set delta $d
		set name $k
	    }
	}
	return $name
    }

    # # ## ### ##### ######## ############# ######################
    ## Instance data, database tables as arrays, keyed by direction
    ## and alias names.

    # Standard directions, the eight sections of the compass rose,
    # with angles and opposite, complementary direction.
    #
    #  135   90  45
    #     nw n ne
    #       \|/
    # 180 w -*- e 0
    #       /|\.
    #     sw s se
    #  225  270  315

    variable myinfo -array {
	east       {angle   0  opposite west     }
	northeast  {angle  45  opposite southwest}
	north      {angle  90  opposite south    }
	northwest  {angle 135  opposite southeast}
	west       {angle 180  opposite east     }
	southwest  {angle 225  opposite northeast}
	south      {angle 270  opposite north    }
	southeast  {angle 315  opposite northwest}

	center     {}
    }

    # Predefined aliases for the standard directions
    # Cardinal and intermediate directions.
    # Names and appropriate unicode symbols.
    variable myalias -array {
	c         center

	w         west         left       west         \u2190 west
	s         south        down       south        \u2191 north
	e         east         right      east         \u2192 east
	n         north        up         north        \u2193 south

	t         north        top        north	       r      east
	b         south        bottom     south	       l      west
	bot       south

	nw        northwest    up-left    northwest    \u2196 northwest
	ne        northeast    up-right   northeast    \u2197 northeast
	se        southeast    down-right southeast    \u2198 southeast
	sw        southwest    down-left  southwest    \u2199 southwest

	upleft    northwest    leftup     northwest	
	upright   northeast    rightup    northeast
	downright southeast    rightdown  southeast
	downleft  southwest    leftdown   southwest	
    }

    ##
    # # ## ### ##### ######## ############# ######################
}

# # ## ### ##### ######## ############# ######################
## Ready

package provide diagram::direction 1