This file is indexed.

/usr/share/tcltk/tcllib1.14/transfer/tqueue.tcl is in tcllib 1.14-dfsg-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
# -*- tcl -*-
# ### ### ### ######### ######### #########
##
# Transfer class built on top of the basic facilities. Accepts many
# transfer requests, any time, and executes them serially. Each
# request has its own progress and completion commands.
#
# Note: The output channel used is part of the queue, and not
#       contained in the transfer requests themselves. Otherwise
#       we would not need a queue and serialized execution.
#
# Instances also have a general callback to report the instance status
# (#pending transfer requests, busy).

# ### ### ### ######### ######### #########
## Requirements

package require transfer::copy ; # Basic transfer facilities
package require struct::queue  ; # Request queue
package require snit           ; # OO system
package require Tcl 8.4

namespace eval ::transfer::copy::queue {
    namespace import ::transfer::copy::options
    namespace import ::transfer::copy::doChan
    namespace import ::transfer::copy::doString
}

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

snit::type ::transfer::copy::queue {
    # ### ### ### ######### ######### #########
    ## API

    option -on-status-change {}

    constructor {thechan args} {}
    method put     {request} {}
    method busy    {} {}
    method pending {} {}

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

    constructor {thechan args} {
	if {![llength [file channels $chan]]} {
	    return -code error "Channel \"$chan\" does not exist"
	}

	set chan  $thechan
	set queue [struct::queue ${selfns}::queue]
	set busy  0

	$self configurelist $args
	return
    }

    destructor {
	if {$queue eq ""} return
	$queue destroy
	return
    }

    method put {request} {
	# Request syntax: type dataref ?options?
	# Accepted options are those of 'transfer::transmit::copy',
	# etc.

	# We parse out the completion callback so that we can use it
	# directly. This also checks the request for basic validity.

	if {[llength $request] < 2} {
	    return -code error "Bad request: Not enough elements"
	}

	set type [lindex $request 0]
	switch -exact -- $type {
	    chan - string {}
	    default {
		return -code error "Bad request: Unknown type \"$type\", expected chan, or string"
	    }
	}

	set options [lrange $request 2 end]
	if {[catch {
	    options $chan $options opts
	} res]} {
	    return -code error "Bad request: $res"
	}

	set ref [lindex $request 1]

	# We store the fully parsed request. Later
	# we call lower-level copy functionality
	# which avoids a reparsing.

	$queue put [list $type $ref [array get opts]]

	# Start the engine executing transfers in the background, if
	# it is not already running.

	if {!$busy} {
	    after 0 [mymethod Transfer]
	}

	$self ReportStatus
	return
    }

    method busy {} {
	return $busy
    }

    method pending {} {
	return [$queue size]
    }

    # ### ### ### ######### ######### #########
    ## Internal helper commands

    method Transfer {} {
	# Get the next pending request. It is already fully-parsed.

	foreach {type ref o} [$queue get] break
	array set opts $o

	# Save the actual completion callback and redirect the
	# completion of the copy operation to ourselves for proper
	# management.

	set opts(-command) [mymethod \
		Done $opts(-command)]

	# Start the transfer. We catch this as it can fail immediately
	# (example: string-type copy and not enough data). We go
	# through 'Done' for the reporting of such errors to avoid
	# forgetting all the other management stuff (like the engine
	# forced to stop).

	set busy 1
	$self ReportStatus

	switch -exact -- $type {
	    chan {
		set code [catch {
		    doChan $ref $chan opts
		} res]
	    }
	    string {
		set code [catch {
		    doString $ref $chan opts
		} res]
	    }
	}

	if {$code} {
	    $self Done $command 0 $res
	}

	return
    }

    method Done {command args} {
	# args is either (n)
	#             or (n errormessage)

	# A transfer ending in an error causes the instance to stop
	# processing requests. I.e. all requests waiting after the
	# failed one are not executed anymore.

	if {[llength $args] == 2} {
	    set busy 0
	    $self ReportStatus
	    $self Notify $command $args
	    return
	}

	# Depending on the status of the queue of pending requests we
	# either trigger the start of the next transfer, or stop the
	# engine. The completion of the current transfer however is
	# unconditionally reported through its completion callback.

	if {[$queue size]} {
	    after 0 [mymethod Transfer]
	} else {
	    set busy 0
	    $self ReportStatus
	}

	$self Notify $command $args
	return
    }

    method ReportStatus {} {
	if {![llength $options(-on-status-change)]} return
	uplevel #0 [linsert $options(-on-status-change) end $self [$queue size] $busy]
	return
    }

    method Notify {cmd alist} {
	foreach a $args {lappend cmd $a}
	uplevel #0 $cmd
    }

    # ### ### ### ######### ######### #########
    ## Data structures
    ## - Channel the transfered data is written to
    ## - Queue of pending requests.

    variable chan  {}
    variable queue {}
    variable busy  0

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

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

package provide transfer::copy::queue 0.1