xref: /openbsd-src/gnu/usr.bin/perl/os2/OS2/OS2-REXX/REXX.pm (revision e068048151d29f2562a32185e21a8ba885482260)
1b39c5158Smillertpackage OS2::REXX;
2b39c5158Smillert
3b39c5158Smillertrequire Exporter;
4b39c5158Smillertuse XSLoader;
5b39c5158Smillertrequire OS2::DLL;
6b39c5158Smillert
7b39c5158Smillert@ISA = qw(Exporter);
8b39c5158Smillert# Items to export into callers namespace by default
9b39c5158Smillert# (move infrequently used names to @EXPORT_OK below)
10b39c5158Smillert@EXPORT = qw(REXX_call REXX_eval REXX_eval_with);
11b39c5158Smillert# Other items we are prepared to export if requested
12b39c5158Smillert@EXPORT_OK = qw(drop register);
13b39c5158Smillert
14*e0680481Safresh1$VERSION = '1.06';
15b39c5158Smillert
16b39c5158Smillert# We cannot just put OS2::DLL in @ISA, since some scripts would use
17b39c5158Smillert# function interface, not method interface...
18b39c5158Smillert
19b39c5158Smillert*_call = \&OS2::DLL::_call;
20b39c5158Smillert*load = \&OS2::DLL::load;
21b39c5158Smillert*find = \&OS2::DLL::find;
22b39c5158Smillert
23b39c5158SmillertXSLoader::load 'OS2::REXX';
24b39c5158Smillert
25b39c5158Smillert# Preloaded methods go here.  Autoload methods go after __END__, and are
26b39c5158Smillert# processed by the autosplit program.
27b39c5158Smillert
28b39c5158Smillertsub register {_register($_) for @_}
29b39c5158Smillert
30b39c5158Smillertsub prefix
31b39c5158Smillert{
32b39c5158Smillert	my $self = shift;
33b39c5158Smillert	$self->{Prefix} = shift;
34b39c5158Smillert}
35b39c5158Smillert
36b39c5158Smillertsub queue
37b39c5158Smillert{
38b39c5158Smillert	my $self = shift;
39b39c5158Smillert	$self->{Queue} = shift;
40b39c5158Smillert}
41b39c5158Smillert
42b39c5158Smillertsub drop
43b39c5158Smillert{				# Supposedly should drop anything with
44b39c5158Smillert                                # the given prefix. Unfortunately a
45b39c5158Smillert                                # loop is needed after fixpack17.
46b39c5158Smillert&OS2::REXX::_drop(@_);
47b39c5158Smillert}
48b39c5158Smillert
49b39c5158Smillertsub dropall
50b39c5158Smillert{				# Supposedly should drop anything with
51b39c5158Smillert                                # the given prefix. Unfortunately a
52b39c5158Smillert                                # loop is needed after fixpack17.
53b39c5158Smillert  &OS2::REXX::_drop(@_);	# Try to drop them all.
54b39c5158Smillert  my $name;
55b39c5158Smillert  for (@_) {
56b39c5158Smillert    if (/\.$/) {
57b39c5158Smillert      OS2::REXX::_fetch('DUMMY'); # reset REXX's first/next iterator
58b39c5158Smillert      while (($name) = OS2::REXX::_next($_)) {
59b39c5158Smillert	OS2::REXX::_drop($_ . $name);
60b39c5158Smillert      }
61b39c5158Smillert    }
62b39c5158Smillert  }
63b39c5158Smillert}
64b39c5158Smillert
65b39c5158Smillertsub TIESCALAR
66b39c5158Smillert{
67b39c5158Smillert	my ($obj, $name) = @_;
68b39c5158Smillert	$name =~ s/^([\w!?]+)/\U$1\E/;
69b39c5158Smillert	return bless \$name, OS2::REXX::_SCALAR;
70b39c5158Smillert}
71b39c5158Smillert
72b39c5158Smillertsub TIEARRAY
73b39c5158Smillert{
74b39c5158Smillert	my ($obj, $name) = @_;
75b39c5158Smillert	$name =~ s/^([\w!?]+)/\U$1\E/;
76b39c5158Smillert	return bless [$name, 0], OS2::REXX::_ARRAY;
77b39c5158Smillert}
78b39c5158Smillert
79b39c5158Smillertsub TIEHASH
80b39c5158Smillert{
81b39c5158Smillert	my ($obj, $name) = @_;
82b39c5158Smillert	$name =~ s/^([\w!?]+)/\U$1\E/;
83b39c5158Smillert	return bless {Stem => $name}, OS2::REXX::_HASH;
84b39c5158Smillert}
85b39c5158Smillert
86b39c5158Smillert#############################################################################
87b39c5158Smillertpackage OS2::REXX::_SCALAR;
88b39c5158Smillert
89b39c5158Smillertsub FETCH
90b39c5158Smillert{
91b39c5158Smillert	return OS2::REXX::_fetch(${$_[0]});
92b39c5158Smillert}
93b39c5158Smillert
94b39c5158Smillertsub STORE
95b39c5158Smillert{
96b39c5158Smillert	return OS2::REXX::_set(${$_[0]}, $_[1]);
97b39c5158Smillert}
98b39c5158Smillert
99b39c5158Smillertsub DESTROY
100b39c5158Smillert{
101b39c5158Smillert	return OS2::REXX::_drop(${$_[0]});
102b39c5158Smillert}
103b39c5158Smillert
104b39c5158Smillert#############################################################################
105b39c5158Smillertpackage OS2::REXX::_ARRAY;
106b39c5158Smillert
107b39c5158Smillertsub FETCH
108b39c5158Smillert{
109b39c5158Smillert	$_[0]->[1] = $_[1] if $_[1] > $_[0]->[1];
110b39c5158Smillert	return OS2::REXX::_fetch($_[0]->[0].'.'.(0+$_[1]));
111b39c5158Smillert}
112b39c5158Smillert
113b39c5158Smillertsub STORE
114b39c5158Smillert{
115b39c5158Smillert	$_[0]->[1] = $_[1] if $_[1] > $_[0]->[1];
116b39c5158Smillert	return OS2::REXX::_set($_[0]->[0].'.'.(0+$_[1]), $_[2]);
117b39c5158Smillert}
118b39c5158Smillert
119b39c5158Smillert#############################################################################
120b39c5158Smillertpackage OS2::REXX::_HASH;
121b39c5158Smillert
122b39c5158Smillertrequire Tie::Hash;
123b39c5158Smillert@ISA = ('Tie::Hash');
124b39c5158Smillert
125b39c5158Smillertsub FIRSTKEY
126b39c5158Smillert{
127b39c5158Smillert	my ($self) = @_;
128b39c5158Smillert	my $stem = $self->{Stem};
129b39c5158Smillert
130b39c5158Smillert	delete $self->{List} if exists $self->{List};
131b39c5158Smillert
132b39c5158Smillert	my @list = ();
133b39c5158Smillert	my ($name, $value);
134b39c5158Smillert	OS2::REXX::_fetch('DUMMY'); # reset REXX's first/next iterator
135b39c5158Smillert	while (($name) = OS2::REXX::_next($stem)) {
136b39c5158Smillert		push @list, $name;
137b39c5158Smillert	}
138b39c5158Smillert	my $key = pop @list;
139b39c5158Smillert
140b39c5158Smillert	$self->{List} = \@list;
141b39c5158Smillert	return $key;
142b39c5158Smillert}
143b39c5158Smillert
144b39c5158Smillertsub NEXTKEY
145b39c5158Smillert{
146b39c5158Smillert	return pop @{$_[0]->{List}};
147b39c5158Smillert}
148b39c5158Smillert
149b39c5158Smillertsub EXISTS
150b39c5158Smillert{
151b39c5158Smillert	return defined OS2::REXX::_fetch($_[0]->{Stem}.$_[1]);
152b39c5158Smillert}
153b39c5158Smillert
154b39c5158Smillertsub FETCH
155b39c5158Smillert{
156b39c5158Smillert	return OS2::REXX::_fetch($_[0]->{Stem}.$_[1]);
157b39c5158Smillert}
158b39c5158Smillert
159b39c5158Smillertsub STORE
160b39c5158Smillert{
161b39c5158Smillert	return OS2::REXX::_set($_[0]->{Stem}.$_[1], $_[2]);
162b39c5158Smillert}
163b39c5158Smillert
164b39c5158Smillertsub DELETE
165b39c5158Smillert{
166b39c5158Smillert	OS2::REXX::_drop($_[0]->{Stem}.$_[1]);
167b39c5158Smillert}
168b39c5158Smillert
169b39c5158Smillert#############################################################################
170b39c5158Smillertpackage OS2::REXX;
171b39c5158Smillert
172b39c5158Smillert1;
173b39c5158Smillert__END__
174b39c5158Smillert
175b39c5158Smillert=head1 NAME
176b39c5158Smillert
177b39c5158SmillertOS2::REXX - access to DLLs with REXX calling convention and REXX runtime.
178b39c5158Smillert
179b39c5158Smillert=head2 NOTE
180b39c5158Smillert
181b39c5158SmillertBy default, the REXX variable pool is not available, neither
182b39c5158Smillertto Perl, nor to external REXX functions. To enable it, you need to put
183b39c5158Smillertyour code inside C<REXX_call> function.  REXX functions which do not use
184b39c5158Smillertvariables may be usable even without C<REXX_call> though.
185b39c5158Smillert
186b39c5158Smillert=head1 SYNOPSIS
187b39c5158Smillert
188b39c5158Smillert	use OS2::REXX;
189b39c5158Smillert	$ydb = load OS2::REXX "ydbautil" or die "Cannot load: $!";
190b39c5158Smillert	@pid = $ydb->RxProcId();
191b39c5158Smillert	REXX_call {
192b39c5158Smillert	  tie $s, OS2::REXX, "TEST";
193b39c5158Smillert	  $s = 1;
194b39c5158Smillert	};
195b39c5158Smillert
196b39c5158Smillert=head1 DESCRIPTION
197b39c5158Smillert
198b39c5158Smillert=head2 Load REXX DLL
199b39c5158Smillert
200b39c5158Smillert	$dll = load OS2::REXX NAME [, WHERE];
201b39c5158Smillert
202b39c5158SmillertNAME is DLL name, without path and extension.
203b39c5158Smillert
204b39c5158SmillertDirectories are searched WHERE first (list of dirs), then environment
205b39c5158Smillertpaths PERL5REXX, PERLREXX, PATH or, as last resort, OS/2-ish search
206b39c5158Smillertis performed in default DLL path (without adding paths and extensions).
207b39c5158Smillert
208b39c5158SmillertThe DLL is not unloaded when the variable dies.
209b39c5158Smillert
210b39c5158SmillertReturns DLL object reference, or undef on failure.
211b39c5158Smillert
212b39c5158Smillert=head2 Define function prefix:
213b39c5158Smillert
214b39c5158Smillert	$dll->prefix(NAME);
215b39c5158Smillert
216b39c5158SmillertDefine the prefix of external functions, prepended to the function
217b39c5158Smillertnames used within your program, when looking for the entries in the
218b39c5158SmillertDLL.
219b39c5158Smillert
220b39c5158Smillert=head2 Example
221b39c5158Smillert
222b39c5158Smillert		$dll = load OS2::REXX "RexxBase";
223b39c5158Smillert		$dll->prefix("RexxBase_");
224b39c5158Smillert		$dll->Init();
225b39c5158Smillert
226b39c5158Smillertis the same as
227b39c5158Smillert
228b39c5158Smillert		$dll = load OS2::REXX "RexxBase";
229b39c5158Smillert		$dll->RexxBase_Init();
230b39c5158Smillert
231b39c5158Smillert=head2 Define queue:
232b39c5158Smillert
233b39c5158Smillert	$dll->queue(NAME);
234b39c5158Smillert
235b39c5158SmillertDefine the name of the REXX queue passed to all external
236b39c5158Smillertfunctions of this module. Defaults to "SESSION".
237b39c5158Smillert
238b39c5158SmillertCheck for functions (optional):
239b39c5158Smillert
240b39c5158Smillert	BOOL = $dll->find(NAME [, NAME [, ...]]);
241b39c5158Smillert
242b39c5158SmillertReturns true if all functions are available.
243b39c5158Smillert
244b39c5158Smillert=head2 Call external REXX function:
245b39c5158Smillert
246b39c5158Smillert	$dll->function(arguments);
247b39c5158Smillert
248b39c5158SmillertReturns the return string if the return code is 0, else undef.
249b39c5158SmillertDies with error message if the function is not available.
250b39c5158Smillert
251b39c5158Smillert=head1 Accessing REXX-runtime
252b39c5158Smillert
253b39c5158SmillertWhile calling functions with REXX signature does not require the presence
254b39c5158Smillertof the system REXX DLL, there are some actions which require REXX-runtime
255b39c5158Smillertpresent. Among them is the access to REXX variables by name.
256b39c5158Smillert
257b39c5158SmillertOne enables REXX runtime by bracketing your code by
258b39c5158Smillert
259b39c5158Smillert	REXX_call BLOCK;
260b39c5158Smillert
261b39c5158Smillert(trailing semicolon required!) or
262b39c5158Smillert
263b39c5158Smillert	REXX_call \&subroutine_name;
264b39c5158Smillert
265b39c5158SmillertInside such a call one has access to REXX variables (see below).
266b39c5158Smillert
267b39c5158SmillertAn alternative way to execute code inside a REXX compartment is
268b39c5158Smillert
269b39c5158Smillert	REXX_eval EXPR;
270b39c5158Smillert	REXX_eval_with EXPR,
271b39c5158Smillert		subroutine_name_in_REXX => \&Perl_subroutine
272b39c5158Smillert
273b39c5158SmillertHere C<EXPR> is a REXX code to run; to execute Perl code one needs to put
274b39c5158Smillertit inside Perl_subroutine(), and call this subroutine from REXX, as in
275b39c5158Smillert
276b39c5158Smillert	REXX_eval_with <<EOE, foo => sub { 123 * shift };
277b39c5158Smillert	  say foo(2)
278b39c5158Smillert	EOE
279b39c5158Smillert
280b39c5158SmillertIf one needs more Perl subroutines available, one can "import" them into
281b39c5158SmillertREXX from inside Perl_subroutine(); since REXX is not case-sensitive,
282b39c5158Smillertthe names should be uppercased.
283b39c5158Smillert
284b39c5158Smillert	use OS2::REXX 'register';
285b39c5158Smillert
286b39c5158Smillert	sub BAR { 123 + shift}
287b39c5158Smillert	sub BAZ { 789 }
288b39c5158Smillert	sub importer { register qw(BAR BAZ) }
289b39c5158Smillert
290b39c5158Smillert	REXX_eval_with <<'EOE', importer => \&importer;
291b39c5158Smillert	  call importer
292b39c5158Smillert	  say bar(34)
293b39c5158Smillert	  say baz()
294b39c5158Smillert	EOE
295b39c5158Smillert
296b39c5158Smillert=head2 Bind scalar variable to REXX variable:
297b39c5158Smillert
298b39c5158Smillert	tie $var, OS2::REXX, "NAME";
299b39c5158Smillert
300b39c5158Smillert=head2 Bind array variable to REXX stem variable:
301b39c5158Smillert
302b39c5158Smillert	tie @var, OS2::REXX, "NAME.";
303b39c5158Smillert
304b39c5158SmillertOnly scalar operations work so far. No array assignments, no array
305b39c5158Smillertoperations, ... FORGET IT.
306b39c5158Smillert
307b39c5158Smillert=head2 Bind hash array variable to REXX stem variable:
308b39c5158Smillert
309b39c5158Smillert	tie %var, OS2::REXX, "NAME.";
310b39c5158Smillert
311b39c5158SmillertTo access all visible REXX variables via hash array, bind to "";
312b39c5158Smillert
313b39c5158SmillertNo array assignments. No array operations, other than hash array
314b39c5158Smillertoperations. Just like the *dbm based implementations.
315b39c5158Smillert
316b39c5158SmillertFor the usual REXX stem variables, append a "." to the name,
317b39c5158Smillertas shown above. If the hash key is part of the stem name, for
318b39c5158Smillertexample if you bind to "", you cannot use lower case in the stem
319b39c5158Smillertpart of the key and it is subject to character set restrictions.
320b39c5158Smillert
321b39c5158Smillert=head2 Erase individual REXX variables (bound or not):
322b39c5158Smillert
323b39c5158Smillert	OS2::REXX::drop("NAME" [, "NAME" [, ...]]);
324b39c5158Smillert
325b39c5158Smillert=head2 Erase REXX variables with given stem (bound or not):
326b39c5158Smillert
327b39c5158Smillert	OS2::REXX::dropall("STEM" [, "STEM" [, ...]]);
328b39c5158Smillert
329b39c5158Smillert=head2 Make Perl functions available in REXX:
330b39c5158Smillert
331b39c5158Smillert	OS2::REXX::register("NAME" [, "NAME" [, ...]]);
332b39c5158Smillert
333b39c5158SmillertSince REXX is not case-sensitive, the names should be uppercase.
334b39c5158Smillert
335b39c5158Smillert=head1 Subcommand handlers
336b39c5158Smillert
337b39c5158SmillertBy default, the executed REXX code runs without any default subcommand
338b39c5158Smillerthandler present.  A subcommand handler named C<PERLEVAL> is defined, but
339b39c5158Smillertnot made a default.  Use C<ADDRESS PERLEVAL> REXX command to make it a default
340b39c5158Smillerthandler; alternatively, use C<ADDRESS Handler WhatToDo> to direct a command
341b39c5158Smillertto the handler you like.
342b39c5158Smillert
343b39c5158SmillertExperiments show that the handler C<CMD> is also available; probably it is
344b39c5158Smillertprovided by the REXX runtime.
345b39c5158Smillert
346b39c5158Smillert=head1 Interfacing from REXX to Perl
347b39c5158Smillert
348b39c5158SmillertThis module provides an interface from Perl to REXX, and from REXX-inside-Perl
349b39c5158Smillertback to Perl.  There is an alternative scenario which allows usage of Perl
350b39c5158Smillertfrom inside REXX.
351b39c5158Smillert
352b39c5158SmillertA DLL F<PerlRexx> provides an API to Perl as REXX functions
353b39c5158Smillert
354b39c5158Smillert  PERL
355b39c5158Smillert  PERLTERM
356b39c5158Smillert  PERLINIT
357b39c5158Smillert  PERLEXIT
358b39c5158Smillert  PERLEVAL
359b39c5158Smillert  PERLLASTERROR
360b39c5158Smillert  PERLEXPORTALL
361b39c5158Smillert  PERLDROPALL
362b39c5158Smillert  PERLDROPALLEXIT
363b39c5158Smillert
364b39c5158SmillertA subcommand handler C<PERLEVALSUBCOMMAND> can also be registered.  Calling
365b39c5158Smillertthe function PERLEXPORTALL() exports all these functions, as well as
366b39c5158Smillertexports this subcommand handler under the name C<EVALPERL>.  PERLDROPALL()
367b39c5158Smillertinverts this action (and unloads PERLEXPORTALL() as well).  In particular
368b39c5158Smillert
369b39c5158Smillert  rc = RxFuncAdd("PerlExportAll", 'PerlRexx', "PERLEXPORTALL")
370b39c5158Smillert  rc = PerlExportAll()
371b39c5158Smillert  res = PERLEVAL(perlarg)
372b39c5158Smillert  ADDRESS EVALPERL perlarg1
373b39c5158Smillert  rc = PerlDropAllExit()
374b39c5158Smillert
375b39c5158Smillertloads all the functions above, evals the Perl code in the REXX variable
376b39c5158SmillertC<perlarg>, putting the result into the REXX variable C<res>,
377b39c5158Smillertthen evals the Perl code in the REXX variable C<perlarg1>, and, finally,
378b39c5158Smillertdrops the loaded functions and the subcommand handler, deinitializes
379b39c5158Smillertthe Perl interpreter, and exits the Perl's C runtime library.
380b39c5158Smillert
381b39c5158SmillertPERLEXIT() or PERLDROPALLEXIT() should be called as the last command of
382b39c5158Smillertthe REXX program.  (This is considered as a bug.)  Their purpose is to flush
383b39c5158Smillertall the output buffers of the Perl's C runtime library.
384b39c5158Smillert
385b39c5158SmillertC<PERLLASTERROR> gives the reason for the failure of the last PERLEVAL().
386b39c5158SmillertIt is useful inside C<signal on syntax> handler.  PERLINIT() and PERLTERM()
387b39c5158Smillertinitialize and deinitialize the Perl interpreter.
388b39c5158Smillert
389b39c5158SmillertC<PERLEVAL(string)> initializes the Perl interpreter (if needed), and
390b39c5158Smillertevaluates C<string> as Perl code.  The result is returned to REXX stringified,
391b39c5158Smillertundefined result is considered as failure.
392b39c5158Smillert
393b39c5158SmillertC<PERL(string)> does the same as C<PERLEVAL(string)> wrapped by calls to
394b39c5158SmillertPERLINIT() and PERLEXIT().
395b39c5158Smillert
396b39c5158Smillert=head1 NOTES
397b39c5158Smillert
398b39c5158SmillertNote that while function and variable names are case insensitive in the
399b39c5158SmillertREXX language, function names exported by a DLL and the REXX variables
400b39c5158Smillert(as seen by Perl through the chosen API) are all case sensitive!
401b39c5158Smillert
402b39c5158SmillertMost REXX DLLs export function names all upper case, but there are a
403b39c5158Smillertfew which export mixed case names (such as RxExtras). When trying to
404b39c5158Smillertfind the entry point, both exact case and all upper case are searched.
405b39c5158SmillertIf the DLL exports "RxNap", you have to specify the exact case, if it
406b39c5158Smillertexports "RXOPEN", you can use any case.
407b39c5158Smillert
408b39c5158SmillertTo avoid interfering with subroutine names defined by Perl (DESTROY)
409b39c5158Smillertor used within the REXX module (prefix, find), it is best to use mixed
410b39c5158Smillertcase and to avoid lowercase only or uppercase only names when calling
411b39c5158SmillertREXX functions. Be consistent. The same function written in different
412b39c5158Smillertways results in different Perl stubs.
413b39c5158Smillert
414b39c5158SmillertThere is no REXX interpolation on variable names, so the REXX variable
415b39c5158Smillertname TEST.ONE is not affected by some other REXX variable ONE. And it
416b39c5158Smillertis not the same variable as TEST.one!
417b39c5158Smillert
418b39c5158SmillertYou cannot call REXX functions which are not exported by the DLL.
419b39c5158SmillertWhile most DLLs export all their functions, some, like RxFTP, export
420b39c5158Smillertonly "...LoadFuncs", which registers the functions within REXX only.
421b39c5158Smillert
422b39c5158SmillertYou cannot call 16-bit DLLs. The few interesting ones I found
423b39c5158Smillert(FTP,NETB,APPC) do not export their functions.
424b39c5158Smillert
425b39c5158SmillertI do not know whether the REXX API is reentrant with respect to
426b39c5158Smillertexceptions (signals) when the REXX top-level exception handler is
427b39c5158Smillertoverridden. So unless you know better than I do, do not access REXX
428b39c5158Smillertvariables (probably tied to Perl variables) or call REXX functions
429b39c5158Smillertwhich access REXX queues or REXX variables in signal handlers.
430b39c5158Smillert
431*e0680481Safresh1See F<t/rx*.t> and the next section for examples.
432b39c5158Smillert
433b39c5158Smillert=head1 EXAMPLE
434b39c5158Smillert
435b39c5158Smillert use OS2::REXX;
436b39c5158Smillert
437b39c5158Smillert sub Ender::DESTROY { $vrexx->VExit; print "Exiting...\n" }
438b39c5158Smillert
439b39c5158Smillert $vrexx = OS2::REXX->load('VREXX');
440b39c5158Smillert REXX_call {			# VOpenWindow takes a stem
441b39c5158Smillert   local $SIG{TERM} = sub {die}; # enable Ender::DESTROY
442b39c5158Smillert   local $SIG{INT} = sub {die};	# enable Ender::DESTROY
443b39c5158Smillert
444b39c5158Smillert   $code = $vrexx->VInit;
445b39c5158Smillert   print "Init code = `$code'\n";
446b39c5158Smillert   die "error initializing VREXX" if $code eq 'ERROR';
447b39c5158Smillert
448b39c5158Smillert   my $ender = bless [], 'Ender'; # Call Ender::DESTROY on exit
449b39c5158Smillert
450b39c5158Smillert   print "VREXX Version ", $vrexx->VGetVersion, "\n";
451b39c5158Smillert
452b39c5158Smillert   tie %pos, 'OS2::REXX', 'POS.' or die;
453b39c5158Smillert   %pos = ( LEFT   => 0, RIGHT  => 7, TOP    => 5, BOTTOM => 0 );
454b39c5158Smillert
455b39c5158Smillert   $id = $vrexx->VOpenWindow('To disconnect:', 'WHITE', 'POS');
456b39c5158Smillert   $vrexx->VForeColor($id, 'BLACK');
457b39c5158Smillert   $vrexx->VSetFont($id, 'TIME', '30');
458b39c5158Smillert   $tlim = time + 60;
459b39c5158Smillert   while ( ($r = $tlim - time) >= 0 ) {
460b39c5158Smillert     $vrexx->VClearWindow($id);
461b8851fccSafresh1     $vrexx->VSay($id, 100, 50, (sprintf "%02i:%02i", int($r/60),
462b8851fccSafresh1                                                              $r % 60));
463b39c5158Smillert     sleep 1;
464b39c5158Smillert   }
465b39c5158Smillert   print "Close code = `$res'\n" if $res = $vrexx->VCloseWindow($id);
466b39c5158Smillert };
467b39c5158Smillert
468b39c5158Smillert
469b39c5158Smillert
470b39c5158Smillert=head1 ENVIRONMENT
471b39c5158Smillert
472b39c5158SmillertIf C<PERL_REXX_DEBUG> is set, prints trace info on calls to REXX runtime
473b39c5158Smillertenvironment.
474b39c5158Smillert
475b39c5158Smillert=head1 AUTHOR
476b39c5158Smillert
477b39c5158SmillertAndreas Kaiser ak@ananke.s.bawue.de, with additions by Ilya Zakharevich
478b39c5158Smillertilya@math.ohio-state.edu.
479b39c5158Smillert
480b39c5158Smillert=head1 SEE ALSO
481b39c5158Smillert
482b39c5158SmillertL<OS2::DLL>.
483b39c5158Smillert
484b39c5158Smillert=cut
485