#############################################################################
#
# File: capture.icn
#
# Subject: Procedures to echo output to a second file
#
# Author: David A. Gamey
#
# Date: August 14, 1996
#
#############################################################################
#
# This file is in the public domain.
#
#############################################################################
#
# Version: 1.0
#
#############################################################################
#
# Capture is initially called by the user with one argument, the open file
# to contain the echoed output. Then it places itself and several shadow
# procedures between all calls to write, writes & stop. The user never
# need call capture again.
#
# Subsequently, during calls to write, writes, and stop, the approprate
# shadow procedure gains control and calls capture internally. Capture
# then constructs a list of only those elements that direct output to
# &output and calls the original builtin function via the saved name.
# Upon return the shadow routine calls the the original builtin function
# with the full list.
#
# A series of uncaptured output functions have been added to allow output
# to be directed only to &output. These are handy for placing progress
# messages and other comforting information on the screen.
#
# Example:
#
# otherfile := open(...,"w")
#
# capfile := capture(open(filename,"w"))
#
# write("Hello there.",var1,var2," - this should be echoed",
# otherfile,"This should appear once in the other file only")
#
# uncaptured_writes("This will appear once only.")
#
# every i := 1 to 10000 do
# if ( i % 100 ) = 0 then
#
# uncaptured_writes("Progress is ",i,"\r")
#
# close(capfile)
# close(otherfile)
#
#############################################################################
#
# Notes:
#
# 1. stop must be handled specially in its shadow function
# 2. capture is not designed to be turned off
# 3. This may be most useful in systems other than Unix
# (i.e. that don't have a "tee" command)
# 4. Display has not been captured because
# a) display is usually a debugging aid, and capture was
# originally intended to capture screen output to a file
# where a record or audit trail might be required
# b) the display output would be 'down a level' showing the
# locals at the display_capture_ level, although the depth
# argument could easily be incremented to adjust for this
# c) write, writes, and stop handle arguments the same way
# 5. An alternative to having two calls would be to have capture
# call the desired procedure with :
# push(&output,x) ; return p!(y ||| x )
# While this would remove the complexity with stop it would
# probably be slower
#
#############################################################################
#
# History:
#
# 10Jun94 - D.Gamey - added uncaptured i/o routines
# 05Oct94 - D.Gamey - temporarily suspend tracing
# 20Oct94 - D.Gamey - fix no output for f(&null)
# - eliminated global variable and select procedure
#
#############################################################################
procedure capture(p,x)
local keepxi # used in list copy to keep/discard arguments
local xi # equivalent to x[i]
local y # list to hold what needs be echoed
static f # alternate file to echo to
case type(p) of
{
"procedure" :
{
# Internal use, support for (write|writes|stop)_capture_ procedures
runerr(/f & 500) # ensure capture(f) called first
keepxi := 1 # default is to keep elements
y := [] # list for captured elements
every xi := !x do
{
if xi === &output then
keepxi := 1 # copying arguments after &output
else
if type(xi) == "file" then
keepxi := &null # ignore arguments after non-&output
else
if \keepxi then # if copying ...
put(y,xi) # append data element from x to y
}
if ( *y > 0 ) | ( *x = 0 ) then
{
push(y,f) # target output to second file
return 1( p!y, y := &null ) # write it & trash list
}
}
"null" :
{
# Internal use, succeeds if capture is active, fails otherwise
if /f then
fail
else
return
}
"file" :
{
# This case is called externally to establish the capture
# and switch places with the regular routines.
# Normally this is called only once, however
# it can be called subsequently to switch the capture file
if /f then # swap procedures first time only
{
write :=: write_capture_
writes :=: writes_capture_
stop :=: stop_capture_
}
return f := p # save file for future use
}
}
end
#subtitle Support procedures to intercept write, writes, and stop
# these procedures get capture to echo text destined for &output
# then call the original routine.
procedure write_capture_(x[])
local tr
tr := &trace ; &trace := 0 # suspend tracing
capture(write_capture_,x)
return 1( write_capture_!x, &trace := tr )
end
procedure writes_capture_(x[])
local tr
tr := &trace ; &trace := 0 # suspend tracing
capture(writes_capture_,x)
return 1( writes_capture_!x, &trace := tr )
end
procedure stop_capture_(x[])
local tr
tr := &trace ; &trace := 0 # suspend tracing
capture(write_capture_,x) # write, otherwise we stop too soon
return 1( stop_capture_!x, &trace := tr ) # restore trace just in case 'stop' is changed
end
#subtitle Support procedures to provide uncaptured output
procedure uncaptured_write(x[])
local tr
tr := &trace ; &trace := 0 # suspend tracing
return 1( ((capture() & write_capture_) | write)!x, &trace := tr )
end
procedure uncaptured_writes(x[])
local tr
tr := &trace ; &trace := 0 # suspend tracing
return 1( ((capture() & writes_capture_) | writes)!x, &trace := tr )
end
procedure uncaptured_stop(x[])
local tr
tr := &trace ; &trace := 0 # suspend tracing
return 1( ((capture() & stop_capture_) | stop)!x, &trace := tr ) # j.i.c.
end
This page produced by UniDoc on 2021/04/15 @ 23:59:44.