Hi
I am not sure if we have discussed this before - but here goes anyway. Delphi (at least, from from version 2.0 onwards) allows routines that take no parameters to be called with empty brackets appended (e.g., "foo();"), much like C requires. See the test program below. GPC does not allow this. Is there any chance of supporting this in GPC?
This program is valid in Delphi, but not in GPC ...
program adelph; function bar : integer; begin bar := 1; end; procedure foo; begin Writeln (bar ()); end; begin foo (); end.
Best regards, The Chief -------- Prof. Abimbola A. Olowofoyeku (The African Chief) web: http://www.bigfoot.com/~african_chief/
17. April 2004 13:03 schrieb Prof A Olowofoyeku (The African Chief):
Delphi (at least, from from version 2.0 onwards) allows routines that take no parameters to be called with empty brackets appended (e.g., "foo();"), much like C requires. See the test program below. GPC does not allow this. Is there any chance of supporting this in GPC? This program is valid in Delphi, but not in GPC ... begin foo (); end.
What would you think about using braces instead? begin foo {}; end.
I don't think, we should support C-style routines.
Eike
On Sat, 17 Apr 2004, Eike Lange wrote:
- April 2004 13:03 schrieb Prof A Olowofoyeku (The African Chief):
Delphi (at least, from from version 2.0 onwards) allows routines that take no parameters to be called with empty brackets appended (e.g., "foo();"), much like C requires. See the test program below. GPC does not allow this. Is there any chance of supporting this in GPC? This program is valid in Delphi, but not in GPC ... begin foo (); end.
What would you think about using braces instead? begin foo {}; end.
I don't think, we should support C-style routines.
Eike
-- ::NETZ-STREIK:: http://www.gnushi.de/ ::NETZ-STREIK::
Since braces are used for comments, I don't think they should be used for anything else.
Since GPC already has a large degree of Borland compatibility, it makes sense to support the empty parentheses in the manner of Delphi if it's easy to do and doesn't break one of the established standards; It can always be disabled in strict mode.
-------------------------| John L. Ries | Salford Systems | Phone: (619)543-8880 x25 | (760)765-4738 | Cell: (760)445-6122 | -------------------------
John L. Ries wrote:
On Sat, 17 Apr 2004, Eike Lange wrote:
What would you think about using braces instead? begin foo {}; end.
I don't think, we should support C-style routines.
Since braces are used for comments, I don't think they should be used for anything else.
That was his point. Think about it.
Prof A Olowofoyeku (The African Chief) wrote:
I do not use the empty brackets when coding myself. As I said, it is for compatibility. Having just spent about an hour dealing with this in some existing code that I was porting to GPC, I thought it would have been very nice indeed to have not had to do that. Delphi has had this for nearly 9 years, and it is not going to disappear from Delphi. As long as we want to support Delphi features, we might as well have it (assuming it is easy to implement - which, considering the C backend, I would imagine should not be too difficult).
Syntax is a frontend issue, so that doesn't mean anything (either way).
Waldek Hebisch wrote:
To compile your program one has to add a single line to gpc. However, then also the following "works":
program adelph2; var bar : integer; procedure foo; begin Writeln (bar ()); end; begin bar := 1; foo (); bar() := 2; foo (); end.
I hope that Delphi does not allow my program. Also with my patch Writeln (); is still rejected (builtin functions/procedures are handled differently then user defined ones). So I would estimate that proper support will take 30-150 lines of code.
And what about this:
var a: procedure;
[...]
a () := foo;
If the `()' is to make any sense, this should not be allowed, of course (since a must not be called here). I suppose Delphi doesn't allow this either.
If we want to do it "officially", it must be done properly. I suppose your 30-150 LOC are a good estimate ...
Currently I'm working on other issues. Someday I plan to rewrite the function calling mechanism a little (it's currently a bit messy WRT functional variables etc.; but since there are no urgent bugs in this area, it might not be too soon). Then I'll see if I can do it in such a way that a change like the above becomes easier to do (though I also really don't like it) ...
Frank
On 18 Apr 2004 at 0:03, Frank Heckenbach wrote:
[...]
And what about this:
var a: procedure;
[...]
a () := foo;
If the `()' is to make any sense, this should not be allowed, of course (since a must not be called here). I suppose Delphi doesn't allow this either.
No, it doesn't. It produces this: " Error: Left side cannot be assigned to".
Best regards, The Chief -------- Prof. Abimbola A. Olowofoyeku (The African Chief) web: http://www.bigfoot.com/~african_chief/
On 17 Apr 2004 at 15:20, Eike Lange wrote:
- April 2004 13:03 schrieb Prof A Olowofoyeku (The African Chief): >
Delphi (at least, from from version 2.0 onwards) allows > routines that take no parameters to be called with empty brackets > appended (e.g., "foo();"), much like C requires. See the test > program below. GPC does not allow this. Is there any chance of > supporting this in GPC? > This program is valid in Delphi, but not in GPC ... > begin > foo (); > end.
What would you think about using braces instead? begin foo {}; end.
I don't think, we should support C-style routines.
I do not use the empty brackets when coding myself. As I said, it is for compatibility. Having just spent about an hour dealing with this in some existing code that I was porting to GPC, I thought it would have been very nice indeed to have not had to do that. Delphi has had this for nearly 9 years, and it is not going to disappear from Delphi. As long as we want to support Delphi features, we might as well have it (assuming it is easy to implement - which, considering the C backend, I would imagine should not be too difficult). If it is difficult or messy to support, then I guess I'll just have to live with having to sort things out manually when porting existing Delphi code (or perhaps write a program to do it automatically).
Best regards, The Chief -------- Prof. Abimbola A. Olowofoyeku (The African Chief) web: http://www.bigfoot.com/~african_chief/
Prof A Olowofoyeku (The African Chief) wrote:
Hi
I am not sure if we have discussed this before - but here goes anyway. Delphi (at least, from from version 2.0 onwards) allows routines that take no parameters to be called with empty brackets appended (e.g., "foo();"), much like C requires. See the test program below. GPC does not allow this. Is there any chance of supporting this in GPC?
This program is valid in Delphi, but not in GPC ...
program adelph; function bar : integer; begin bar := 1; end; procedure foo; begin Writeln (bar ()); end; begin foo (); end.
There was a long discussion around November 2002:
http://www.gnu-pascal.de/crystal/gpc/en/thread7244.html
To compile your program one has to add a single line to gpc. However, then also the following "works":
program adelph2; var bar : integer; procedure foo; begin Writeln (bar ()); end; begin bar := 1; foo (); bar() := 2; foo (); end.
I hope that Delphi does not allow my program. Also with my patch Writeln (); is still rejected (builtin functions/procedures are handled differently then user defined ones). So I would estimate that proper support will take 30-150 lines of code.
On 17 Apr 2004 at 23:33, Waldek Hebisch wrote:
[...]
There was a long discussion around November 2002:
Ah, yes! I remember now. I don't think we want to open that can of worms again - except that it seems that the issue has bothered me enough (when doing some porting) for me to raise it twice.
To compile your program one has to add a single line to gpc. However, then also the following "works":
program adelph2; var bar : integer; procedure foo; begin Writeln (bar ()); end; begin bar := 1; foo (); bar() := 2; foo (); end.
I hope that Delphi does not allow my program.
It does not. This is the output: e:\temp>dcc7 adelph2.pas Borland Delphi Version 15.0 Copyright (c) 1983,2002 Borland Software Corporation E:\temp\adelph2.pas(5) Error: Missing operator or semicolon E:\temp\adelph2.pas(10) Error: Missing operator or semicolon E:\temp\adelph2.pas(14)
Also with my patch Writeln (); is still rejected (builtin functions/procedures are handled differently then user defined ones).
Delphi rejects "Writeln ()" as well. AFAICS, the empty brackets are only allowed for parameter-less routines. Since Writeln can take parameters, that code should be rejected.
So I would estimate that proper support will take 30-150 lines of code.
Even with what I have just noted above? If yes, then even though it might seem like too much work, it is probably less work than having to deal with this problem all the time when porting Delphi code (and actually, the code I was porting today was FreePascal code).
If you are not interested in doing the proper support, can you please just send me the single line patch? For me that is a far lesser evil than what I have had to do today. Thanks.
Best regards, The Chief -------- Prof. Abimbola A. Olowofoyeku (The African Chief) web: http://www.bigfoot.com/~african_chief/
Prof A Olowofoyeku (The African Chief) wrote:
Delphi rejects "Writeln ()" as well. AFAICS, the empty brackets are only allowed for parameter-less routines. Since Writeln can take parameters, that code should be rejected.
Does it allow user-defined optional parameters? If so, what about `()' then?
Frank
On 18 Apr 2004 at 1:26, Frank Heckenbach wrote:
Prof A Olowofoyeku (The African Chief) wrote:
Delphi rejects "Writeln ()" as well. AFAICS, the empty brackets are only allowed for parameter-less routines. Since Writeln can take parameters, that code should be rejected.
Does it allow user-defined optional parameters? If so, what about `()' then?
I am not sure what you are referring to here. Are you referring to things similar to "Writeln" which currently require compiler magic under GPC? If so, I guess they would be implemented by the overloading mechanism, and if one of the overloaded routines takes no parameters, then this whould be okay - for example, this is perfectly legal;
procedure baz; overload; begin end;
procedure baz (i : real); overload; begin end;
procedure baz (i : real; j : string); overload; begin end;
procedure baz (i, j : string); overload; begin end;
[.....] baz; baz (); baz (1.0); baz (5.5, 'Chief'); baz ('African', 'Chief');
If you were referring to something like "default parameters", then this is what the Delphi 7 help file says:
"You can omit parentheses when passing all and only the default parameters to a routine. For example, given the procedure procedure DoSomething(X: Real = 1.0; I: Integer = 0; S: string = ''); the following calls are equivalent. DoSomething(); DoSomething;"
Best regards, The Chief -------- Prof. Abimbola A. Olowofoyeku (The African Chief) web: http://www.bigfoot.com/~african_chief/
Prof A Olowofoyeku (The African Chief) wrote:
Does it allow user-defined optional parameters? If so, what about `()' then?
I am not sure what you are referring to here. Are you referring to things similar to "Writeln" which currently require compiler magic under GPC?
(AFAIK, `WriteLn' requires compiler magic in any compiler since it allows for an infinite number of combinations of number and types of arguments.)
If so, I guess they would be implemented by the overloading mechanism, and if one of the overloaded routines takes no parameters, then this whould be okay - for example, this is perfectly legal;
OK.
If you were referring to something like "default parameters", then this is what the Delphi 7 help file says:
"You can omit parentheses when passing all and only the default parameters to a routine. For example, given the procedure procedure DoSomething(X: Real = 1.0; I: Integer = 0; S: string = ''); the following calls are equivalent. DoSomething(); DoSomething;"
That's what I meant.
So we'll have to remember to test these cases when we implement overloading and/or optional parameters.
Frank
Prof A Olowofoyeku (The African Chief) wrote:
Does it allow user-defined optional parameters? If so, what about `()' then?
I am not sure what you are referring to here. Are you referring to things similar to "Writeln" which currently require compiler magic under GPC?
(AFAIK, `WriteLn' requires compiler magic in any compiler since it allows for an infinite number of combinations of number and types of arguments.)
Yes, it cannot be emulated with overloads. Small, common cases could be emulated with overloads, but overloads are finite, and writeln/readln has infinite cases.
Frank Heckenbach wrote:
Prof A Olowofoyeku (The African Chief) wrote:
Does it allow user-defined optional parameters? If so, what about `()' then?
I am not sure what you are referring to here. Are you referring to things similar to "Writeln" which currently require compiler magic under GPC?
(AFAIK, `WriteLn' requires compiler magic in any compiler since it allows for an infinite number of combinations of number and types of arguments.)
writeln(f) (or writeln, defaulting to writeln(output)) is the only pure form. Anything else is defined in terms of shorthand.
writeln(f, a) is expected to expand to "write(f, a); writeln(f);" Similarly, if a is not a single simple object, write(f, a, b) is expected to expand to "write(f, a); write(f, b)". There is no magic, and especially no variable parameter lists. This has been clearly spelled out since the User Manual and Report.
The action of write(f, a) for non text files is spelled out in terms of f^ and put.
Similar things apply to read and readln.
I repeat - there is NO MAGIC.
CBFalconer wrote:
Frank Heckenbach wrote:
(AFAIK, `WriteLn' requires compiler magic in any compiler since it allows for an infinite number of combinations of number and types of arguments.)
writeln(f) (or writeln, defaulting to writeln(output)) is the only pure form. Anything else is defined in terms of shorthand.
writeln(f, a) is expected to expand to "write(f, a); writeln(f);" Similarly, if a is not a single simple object, write(f, a, b) is expected to expand to "write(f, a); write(f, b)". There is no magic, and especially no variable parameter lists. This has been clearly spelled out since the User Manual and Report.
The action of write(f, a) for non text files is spelled out in terms of f^ and put.
Similar things apply to read and readln.
I repeat - there is NO MAGIC.
Semantically not, but syntactically it is magic. You can't define such transformations in Pascal code (not even with GPC's current preprocessor ;-).
This is what I usually mean when talking of magic. On the runtime side you can always do with regular routine calls. The question is which kind of transformations the compiler has to do to get there, or simply whether it's possible (at least in principle) to implement those predefined things in pure Pascal code. For some it's easily possible (e.g. `Odd'), some would require a finite amount of overloading (e.g., `EOLn'), some require a certain amount of untypedness (e.g., `EOF' -- accepting all `file of Foo' types, though they're similar enough in probably any implementation to be able to be handled by common code), some must be able to accept an arbitrary number of parameters of the same type (at least from a certain point; e.g., `Write' on typed files), but AFAIK only `Write[Ln]', `Read[Ln]' (and `WriteStr', `ReadStr' in EP) can have both an arbitrary number of arguments and different types for each argument.
Frank
Prof. Abimbola A. Olowofoyeku (The African Chief) wrote:
Also with my patch Writeln (); is still rejected (builtin functions/procedures are handled differently then user defined ones).
Delphi rejects "Writeln ()" as well. AFAICS, the empty brackets are only allowed for parameter-less routines. Since Writeln can take parameters, that code should be rejected.
If calls to built-ins with empty parethesis are illegal, than the task is easier. The patch below (add 13 lines) should work. With the patch in:
a() := 5;
`a()' is treated as a call, and rejected just like `a(5)'. In
var a: procedure; a := bar();
assignment is rejected (since we do not allow procedural return values). On the other hand, the following works: var a: procedure; .... a := foo; a ();
So I hope that the implementation is reasonably complete.
--- gpc-20030830/p/parse.y 2004-04-17 04:39:59.000000000 +0200 +++ gpc-20030830/p/parse.y 2004-04-18 01:10:51.000000000 +0200 @@ -2509,6 +2509,19 @@ { $$ = build_pascal_pointer_reference ($1); } | variable_or_routine_access_no_parentheses '[' index_expression_list ']' { $$ = build_pascal_array_ref ($1, $3); } + | variable_or_routine_access_no_builtin_function '(' rpar + { + chk_dialect ("empty parenthesis as parameter are", BORLAND_DELPHI); + if ($1 && TREE_CODE ($1) == TYPE_DECL) + { + error ("type cast expects one expression argument"); + $$ = error_mark_node; + } + else if (CALL_METHOD ($1)) + $$ = call_method ($1, NULL_TREE); + else + $$ = build_routine_call ($1, NULL_TREE); + } | variable_or_routine_access_no_builtin_function '(' { $<itype>2 = allow_function_calls (0); } actual_parameter_list rpar_or_error
In case, I have put genereted C files on web page:
http://www.math.uni.wroc.pl/~hebisch/gpc
Waldek Hebisch wrote:
If calls to built-ins with empty parethesis are illegal, than the task is easier. The patch below (add 13 lines) should work. With the patch in:
a() := 5;
`a()' is treated as a call, and rejected just like `a(5)'. In
var a: procedure; a := bar();
assignment is rejected (since we do not allow procedural return values). On the other hand, the following works: var a: procedure; .... a := foo; a ();
So I hope that the implementation is reasonably complete. [...]
I see. If you want it in the next release, please:
- move the code out of parse.y as far as possible (I'm trying to move as much non-parsing code out of it as reasonably possible). Perhaps merge it with the real function call code (below) to a subroutine. This should also save some code duplication.
- For TYPE_DECL, the first check seems superfluous, since there is an error already. Or do we really want both?
- Add some test programs (for all cases discussed here, and perhaps some more). The Chief, perhaps?
Frank
On 18 Apr 2004 at 5:09, Frank Heckenbach wrote:
[...]
I see. If you want it in the next release, please:
move the code out of parse.y as far as possible (I'm trying to move as much non-parsing code out of it as reasonably possible). Perhaps merge it with the real function call code (below) to a subroutine. This should also save some code duplication.
For TYPE_DECL, the first check seems superfluous, since there is an error already. Or do we really want both?
Add some test programs (for all cases discussed here, and perhaps some more). The Chief, perhaps?
I am happy to write test programs. What is the time scale? In fact, I have written a little test program to try out the various cases discussed here (see below). I guess that all I need to do now is to convert each case into a single program that prints "OK" if it is okay?
program adelph3;
var a, b: procedure;
procedure foo (); { ok } begin end;
procedure bar; begin end;
procedure baz; overload; begin end;
procedure baz (i : real); overload; begin end;
procedure baz (i : real; j : string); overload; begin end;
procedure baz (i : string; j : string); overload; begin end;
begin a () := foo; { rejected } a := foo; { ok } b := bar (); { rejected } a (); { ok } b; { ok } baz; { ok } baz (); { ok } baz (1.0); { ok } baz (5.5, 'Chief'); { ok } baz ('African', 'Chief'); { ok } end.
Best regards, The Chief -------- Prof. Abimbola A. Olowofoyeku (The African Chief) web: http://www.bigfoot.com/~african_chief/
Prof A Olowofoyeku (The African Chief) wrote:
- Add some test programs (for all cases discussed here, and perhaps some more). The Chief, perhaps?
I am happy to write test programs. What is the time scale?
A few weeks (I hope). But the sooner the better (especially if any problems will be found).
In fact, I have written a little test program to try out the various cases discussed here (see below). I guess that all I need to do now is to convert each case into a single program that prints "OK" if it is okay?
And a `{ WRONG }' comment for the rejected cases. (Each program can contain one or several expected pass tests or one expected error.)
Frank
On 18 Apr 2004 at 15:34, Frank Heckenbach wrote:
[...]
In fact, I have written a little test program to try out the various cases discussed here (see below). I guess that all I need to do now is to convert each case into a single program that prints "OK" if it is okay?
And a `{ WRONG }' comment for the rejected cases. (Each program can contain one or several expected pass tests or one expected error.)
Attached is a tarball containing a number of test programs (chief54[]) which encapsulate most of the cases we have discussed today (and incorporates most of Waldek's examples).
Best regards, The Chief -------- Prof. Abimbola A. Olowofoyeku (The African Chief) web: http://www.bigfoot.com/~african_chief/
The following section of this message contains a file attachment prepared for transmission using the Internet MIME message format. If you are using Pegasus Mail, or any other MIME-compliant system, you should be able to save it or view it from within your mailer. If you cannot, please ask your system administrator for assistance.
---- File information ----------- File: chief54.tar.gz Date: 18 Apr 2004, 20:43 Size: 675 bytes. Type: Unknown
On 18 Apr 2004 at 3:46, Waldek Hebisch wrote:
[...]
So I hope that the implementation is reasonably complete.
--- gpc-20030830/p/parse.y 2004-04-17 04:39:59.000000000 +0200 +++ gpc-20030830/p/parse.y 2004-04-18 01:10:51.000000000 +0200
[....]
Thanks for the patch!
Best regards, The Chief -------- Prof. Abimbola A. Olowofoyeku (The African Chief) web: http://www.bigfoot.com/~african_chief/
On 18 Apr 2004 at 3:46, Waldek Hebisch wrote:
[...]
So I hope that the implementation is reasonably complete.
--- gpc-20030830/p/parse.y 2004-04-17 04:39:59.000000000 +0200 +++ gpc-20030830/p/parse.y 2004-04-18 01:10:51.000000000 +0200 @@ -2509,6 +2509,19 @@
[...]
Works fine here, except that this (valid in Delphi) is still rejected: procedure foo (); begin end;
Best regards, The Chief -------- Prof. Abimbola A. Olowofoyeku (The African Chief) web: http://www.bigfoot.com/~african_chief/
Prof A Olowofoyeku (The African Chief) wrote:
Works fine here, except that this (valid in Delphi) is still rejected: procedure foo (); begin end;
I see. I have updated the patch to accept the following:
program delfp; type pt = procedure (); ft = function () : integer; var a : pt; b : procedure (); c : ft; d : function () : integer;
function fi : integer; begin fi := 0 end; function fid () : integer; begin fid := 0 end; procedure p ; begin end; procedure pd (); begin end;
begin a := p; a := pd; b := p; b := pd; c := fi; c := fid; d := fi; d := fid; writeln('OK') end .
However, I do not know if the following is accepted by Delphi:
program delf101; procedure pi (i : integer); forward; procedure pi (); begin end; begin end .
On 18 Apr 2004 at 17:55, Waldek Hebisch wrote:
Prof A Olowofoyeku (The African Chief) wrote:
Works fine here, except that this (valid in Delphi) is still rejected: procedure foo (); begin end;
I see. I have updated the patch to accept the following:
program delfp; type pt = procedure (); ft = function () : integer; var a : pt; b : procedure (); c : ft; d : function () : integer;
function fi : integer; begin fi := 0 end; function fid () : integer; begin fid := 0 end; procedure p ; begin end; procedure pd (); begin end;
begin a := p; a := pd; b := p; b := pd; c := fi; c := fid; d := fi; d := fid; writeln('OK') end .
This compiles ok under Delphi, and prints 'OK'.
However, I do not know if the following is accepted by Delphi:
program delf101; procedure pi (i : integer); forward; procedure pi (); begin end; begin end .
It is not accepted. Delphi thinks you are trying to overload 'pi' without doing it properly. This is the error: "E:\temp\delf101.pas(3) Error: Previous declaration of 'pi' was not marked with the 'overload' directive E:\temp\delf101.pas(8) E:\temp\delf101.pas(2) Error: Unsatisfied forward or external declaration: 'pi'"
Now, this is accepted: program delf102; procedure pi (i : integer); overload; begin end; procedure pi (); overload; begin end; begin end.
PS: with respect to implementing the overloading of routines, ITSM that an easy way to do this is to implicitly generate a different asmname for each one, and then call the correct one (via its asmname or "name" attribute), depending on the parameters passed (or perhaps I am just displaying my ignorance about compiler writing here ...).
Best regards, The Chief -------- Prof. Abimbola A. Olowofoyeku (The African Chief) web: http://www.bigfoot.com/~african_chief/
Prof A Olowofoyeku (The African Chief) wrote:
On 18 Apr 2004 at 17:55, Waldek Hebisch wrote:
However, I do not know if the following is accepted by Delphi:
program delf101; procedure pi (i : integer); forward; procedure pi (); begin end; begin end .
It is not accepted. Delphi thinks you are trying to overload 'pi' without doing it properly. This is the error: "E:\temp\delf101.pas(3) Error: Previous declaration of 'pi' was not marked with the 'overload' directive E:\temp\delf101.pas(8) E:\temp\delf101.pas(2) Error: Unsatisfied forward or external declaration: 'pi'"
Now, this is accepted: program delf102; procedure pi (i : integer); overload; begin end; procedure pi (); overload; begin end; begin end.
Well, before we will do overloading we have to finish qualified indentifiers.
In the program above I really wanted `forward' declaration -- the point is how much meaning do the empty parentheses have. And I hope that declarations in interfaces and methods behave the same, so I started with `forward'. It seems that empty parentheses in procedure definition mean no parameteres (while ommited parameters in standard Pascal mean that the compiler should use parameters from forward declaration).
If my interpretation is correct the examples below should be accepted:
{ standard Pascal} procedure pi (i : integer); forward; procedure pi; begin end;
----
procedure pe ; forward; procedure pe (); begin end;
----
procedure pe (); forward; procedure pe ; begin end;
----
procedure pe (); forward; procedure pe (); begin end;
On 18 Apr 2004 at 21:16, Waldek Hebisch wrote:
[...]
In the program above I really wanted `forward' declaration -- the point is how much meaning do the empty parentheses have. And I hope that declarations in interfaces and methods behave the same, so I started with `forward'. It seems that empty parentheses in procedure definition mean no parameteres (while ommited parameters in standard Pascal mean that the compiler should use parameters from forward declaration).
If my interpretation is correct the examples below should be accepted:
{ standard Pascal} procedure pi (i : integer); forward; procedure pi; begin end;
procedure pe ; forward; procedure pe (); begin end;
procedure pe (); forward; procedure pe ; begin end;
procedure pe (); forward; procedure pe (); begin end;
They are all accepted by Delphi and by GPC with your latest patch.
Best regards, The Chief -------- Prof. Abimbola A. Olowofoyeku (The African Chief) web: http://www.bigfoot.com/~african_chief/