Tcl Library Source Code

Check-in [8a5b6fdec2]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Modify [coroutine::util gets/gets_safety/read] to restore any original event handler on the channel, and to not be so busy.
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 8a5b6fdec2b4f5606c9f959653251e9ffc31ffe2107b3813a882c7f4cf009737
User & Date: pooryorick 2022-01-17 23:43:18
Context
2022-01-18
07:43
coroutine: Reduce quoting and add procedure markers. check-in: cb716671f7 user: pooryorick tags: trunk
2022-01-17
23:43
Modify [coroutine::util gets/gets_safety/read] to restore any original event handler on the channel, and to not be so busy. check-in: 8a5b6fdec2 user: pooryorick tags: trunk
22:44
Update the documentation for "longest common subsequence". check-in: d23cf1bb9d user: pooryorick tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to modules/coroutine/coroutine.tcl.

162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
    }
    yield
    return
}

# - -- --- ----- -------- -------------

proc ::coroutine::util::gets {args} {
    # Process arguments.
    # Acceptable syntax:
    # * gets CHAN ?VARNAME?

    if {[llength $args] == 2} {
	# gets CHAN VARNAME
	lassign $args chan varname







|







162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
    }
    yield
    return
}

# - -- --- ----- -------- -------------

proc ::coroutine::util::gets args {
    # Process arguments.
    # Acceptable syntax:
    # * gets CHAN ?VARNAME?

    if {[llength $args] == 2} {
	# gets CHAN VARNAME
	lassign $args chan varname
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
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295





296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351




352
353
354
355
356
357
358
	# necessary error with the proper message.
	tailcall ::chan gets {*}$args
    }

    # Loop until we have a complete line. Yield to the event loop
    # where necessary. During
    set blocking [::chan configure $chan -blocking]
    while {1} {

        ::chan configure $chan -blocking 0


	try {
	    set result [::chan gets $chan line]
	} on error {result opts} {
            ::chan configure $chan -blocking $blocking
            return -code $result -options $opts
	}

	if {[::chan blocked $chan]} {
            ::chan event $chan readable [list [info coroutine]]
            yield
            ::chan event $chan readable {}
        } else {
            ::chan configure $chan -blocking $blocking

            if {[llength $args] == 2} {
                return $result
            } else {
                return $line
            }
        }




    }
}


proc ::coroutine::util::gets_safety {chan limit varname {timeout 120000}} {
    # Process arguments.
    # Acceptable syntax:
    # * gets CHAN ?VARNAME?

    # Loop until we have a complete line. Yield to the event loop
    # where necessary. During
    set blocking [::chan configure $chan -blocking]
    upvar 1 $varname line




    try {
	while {1} {
	    ::chan configure $chan -blocking 0
	    if {[::chan pending input $chan]>= $limit} {
		error {Too many notes, Mozart. Too many notes}
	    }
	    try {
		set result [::chan gets $chan line]
	    } on error {result opts} {
		return -code $result -options $opts
	    }

	    if {[::chan blocked $chan]} {
	  set timeoutevent [::after $timeout [list [info coroutine] timeout]]
		::chan event $chan readable [list [info coroutine] readable]
		set event [yield]
		if {$event eq "timeout"} {
		  error "Connection Timed Out"
		}
		::after cancel $timeoutevent
		::chan event $chan readable {}
	    } else {
		return $result
	    }
	}
    } finally {
        ::chan configure $chan -blocking $blocking

    }
}



# - -- --- ----- -------- -------------

proc ::coroutine::util::read {args} {
    # Process arguments.
    # Acceptable syntax:
    # * read ?-nonewline ? CHAN
    # * read               CHAN ?n?

    if {[llength $args] > 2} {
	# Calling the builtin read command with the bogus arguments
	# gives us the necessary error with the proper message.
	::chan read {*}$args
	return
    }

    set total Inf ; # Number of characters to read. Here: Until eof.
    set chop  no  ; # Boolean flag. Determines if we have to trim a
    #               # \n from the end of the read string.

    if {[llength $args] == 2} {
	lassign $args a b
	if {$a eq "-nonewline"} {
	    set chan $b
	    set chop yes
	} else {
	    lassign $args chan total
	}
    } else {
	lassign $args chan
    }

    # Run the read loop. Yield to the event loop where
    # necessary. Differentiate between loop until eof, and loop until
    # n characters have been read (or eof reached).

    set buf {}






    if {$total eq "Inf"} {
	# Loop until eof.

	while 1 {
	    set blocking [::chan configure $chan -blocking]
	    ::chan configure $chan -blocking 0
	    if {[::chan eof $chan]} {
		break
	    } elseif {[::chan blocked $chan]} {
		::chan event $chan readable [list [info coroutine]]
		yield
		::chan event $chan readable {}
	    }

	    try {
		set result [::chan read $chan]
	    } on error {result opts} {
		::chan configure $chan -blocking $blocking
		return -code $result -options $opts
	    } finally {
		::chan configure $chan -blocking $blocking
	    }
	    append buf $result
	}
    } else {
	# Loop until total characters have been read, or eof found,
	# whichever is first.

	set left $total
	while 1 {
	    set blocking [::chan configure $chan -blocking]
	    ::chan configure $chan -blocking 0

	    if {[::chan eof $chan]} {
		break
	    } elseif {[::chan blocked $chan]} {
		::chan event $chan readable [list [info coroutine]]
		yield
		::chan event $chan readable {}
	    }

	    try {
		set result [::chan read $chan $left]
	    } on error {result opts} {
		::chan configure $chan -blocking $blocking
		return -code $result -options $opts
	    } finally {
		::chan configure $chan -blocking $blocking
	    }

	    append buf $result
	    incr left -[string length $result]
	    if {!$left} {
		break
	    }
	}




    }

    if {$chop && [string index $buf end] eq "\n"} {
	set buf [string range $buf 0 end-1]
    }

    return $buf







|
>
|
|
>
|
|
|
<
|
|

|
<
|
<
|
<
<
|
|
|
|
|
|
>
>
>
>











<

>
>
>
>

|
<










|
<





<





|
>







|


















|















>
>
>
>
>
|
|
<
|
<
<
|
|
|
<
|
<
|

|
|
|
<
|
<
<
|
|
|
|
|
|

|
|
<
<
<
|
|
|
<
|
<
|

|
|
|
<
|
<
<
|

|
|
|
|
|
|
>
>
>
>







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
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304

305


306
307
308

309

310
311
312
313
314

315


316
317
318
319
320
321
322
323
324



325
326
327

328

329
330
331
332
333

334


335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
	# necessary error with the proper message.
	tailcall ::chan gets {*}$args
    }

    # Loop until we have a complete line. Yield to the event loop
    # where necessary. During
    set blocking [::chan configure $chan -blocking]
    set readable [::chan event $chan readable]
    ::chan event $chan readable [list [info coroutine]]
    ::chan configure $chan -blocking 0
    try {
	while 1 {
	    try {
		set result [::chan gets $chan line]
	    } on error {result opts} {

		return -code $result -options $opts
	    }

	    if {[::chan blocked $chan]} {

		yield

	    } else {


		if {[llength $args] == 2} {
		    return $result
		} else {
		    return $line
		}
	    }
	}
    } finally {
	::chan configure $chan -blocking $blocking
	::chan event $chan readable $readable
    }
}


proc ::coroutine::util::gets_safety {chan limit varname {timeout 120000}} {
    # Process arguments.
    # Acceptable syntax:
    # * gets CHAN ?VARNAME?

    # Loop until we have a complete line. Yield to the event loop
    # where necessary. During

    upvar 1 $varname line
    set blocking [::chan configure $chan -blocking]
    ::chan configure $chan -blocking 0
    set readable [::chan event $chan readable]
    ::chan event $chan readable [list [info coroutine] readable]
    try {
	while 1 {

	    if {[::chan pending input $chan]>= $limit} {
		error {Too many notes, Mozart. Too many notes}
	    }
	    try {
		set result [::chan gets $chan line]
	    } on error {result opts} {
		return -code $result -options $opts
	    }

	    if {[::chan blocked $chan]} {
		set timeoutevent [::after $timeout [list [info coroutine] timeout]]

		set event [yield]
		if {$event eq "timeout"} {
		  error "Connection Timed Out"
		}
		::after cancel $timeoutevent

	    } else {
		return $result
	    }
	}
    } finally {
	::chan configure $chan -blocking $blocking
	::chan event $chan readable $readable
    }
}



# - -- --- ----- -------- -------------

proc ::coroutine::util::read args {
    # Process arguments.
    # Acceptable syntax:
    # * read ?-nonewline ? CHAN
    # * read               CHAN ?n?

    if {[llength $args] > 2} {
	# Calling the builtin read command with the bogus arguments
	# gives us the necessary error with the proper message.
	::chan read {*}$args
	return
    }

    set total Inf ; # Number of characters to read. Here: Until eof.
    set chop  no  ; # Boolean flag. Determines if we have to trim a
    #               # \n from the end of the read string.

    if {[llength $args] == 2} {
	lassign $args a b
	if {$a eq {-nonewline}} {
	    set chan $b
	    set chop yes
	} else {
	    lassign $args chan total
	}
    } else {
	lassign $args chan
    }

    # Run the read loop. Yield to the event loop where
    # necessary. Differentiate between loop until eof, and loop until
    # n characters have been read (or eof reached).

    set buf {}

    set blocking [::chan configure $chan -blocking]
    set readable [::chan event $chan readable]
    ::chan event $chan readable [list [info coroutine]]
    ::chan configure $chan -blocking 0
    try {
	if {$total eq "Inf"} {
	    # Loop until eof.

	    while 1 {


		if {[::chan eof $chan]} {
		    break
		} elseif {[::chan blocked $chan]} {

		    yield

		}

		try {
		    set result [::chan read $chan]
		} on error {result opts} {

		    return -code $result -options $opts


		} 
		append buf $result
	    }
	} else {
	    # Loop until total characters have been read, or eof found,
	    # whichever is first.

	    set left $total
	    while 1 {



		if {[::chan eof $chan]} {
		    break
		} elseif {[::chan blocked $chan]} {

		    yield

		}

		try {
		    set result [::chan read $chan $left]
		} on error {result opts} {

		    return -code $result -options $opts


		}

		append buf $result
		incr left -[string length $result]
		if {!$left} {
		    break
		}
	    }
	}
    } finally {
	::chan configure $chan -blocking $blocking
	::chan event $chan readable $readable
    }

    if {$chop && [string index $buf end] eq "\n"} {
	set buf [string range $buf 0 end-1]
    }

    return $buf