Topic: Core language features referring to the standard library?
Author: kanze@gabi-soft.de (James Kanze)
Date: Wed, 18 Sep 2002 01:49:07 +0000 (UTC) Raw View
francis.glassborow@ntlworld.com (Francis Glassborow) wrote in message
news:<Ek80d5CXigh9EwHB@robinton.demon.co.uk>...
> >Again, new and dynamic cast are different: new is an operator,
> >dynamic cast is not.
> Depends which authority you look at. The Standard seems confused,
> referring to some things as operators in one place and expressions in
> another.
In general, "new" or "dynamic_cast" are keywords, "new Whatever" and
"dynamic_cast< Type >( expr )" are expressions. I don't see any
problem.
--
James Kanze mailto:jkanze@caicheuvreux.com
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: francis.glassborow@ntlworld.com (Francis Glassborow)
Date: Wed, 18 Sep 2002 19:36:11 +0000 (UTC) Raw View
In article <3D867D6F.B0D5957C@wizard.net>, James Russell Kuyper Jr.
<kuyper@wizard.net> writes
>They are not overloadable operators (and that's a great relief - think
>about it!). The list of things defined as 'operators' in 13.5p1 is not a
>complete list of operators, it's actually only a list of the
>overloadable operators, though it's not clearly identified as such.
>You'll notice, for instance, that it contains none of the operators
>listed in 13.5p3.
However, it is perhaps unfortunate that 13.5p3 does not list all the
operators that are not overloadable. had it done so we would have a
definitive list of C++ operators.
--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: Allan_W@my-dejanews.com (Allan W)
Date: Thu, 19 Sep 2002 12:44:51 +0000 (UTC) Raw View
> > musiphil@bawi.org (Sungbom Kim) wrote
> > > My understanding of the relationship between the "core language" and the
> > > "standard library" is that, though both constitute "the C++ Language",
> > > the latter is a layer built on top of the layer of the former.
> > > (Please correct me on this matter if I'm wrong.)
> Allan W wrote:
> > An interesting way to categorize sections. Nothing in the standard says
> > this, though (that I know of).
kuyper@wizard.net ("James Russell Kuyper Jr.") wrote
> Section 1.5 p1:
> "Clauses 2 through 16 describe the C++ programming language. ..."
> p2:
> "Clauses 17 through 27 (the _library clauses_) describe the Standard C++
> library, ..."
Thank you. I stand corrected.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: Allan_W@my-dejanews.com (Allan W)
Date: Mon, 16 Sep 2002 22:32:36 +0000 (UTC) Raw View
musiphil@bawi.org (Sungbom Kim) wrote
> My understanding of the relationship between the "core language" and the
> "standard library" is that, though both constitute "the C++ Language",
> the latter is a layer built on top of the layer of the former.
> (Please correct me on this matter if I'm wrong.)
An interesting way to categorize sections. Nothing in the standard says
this, though (that I know of).
> But there are some things that contradict this understanding of mine;
> some core language features seem to refer to and depend on the standard
> library! They include (std:: qualifier omitted for brevity)
>
> [normal types]
> * ptrdiff_t, size_t (defined in <cstddef>)
> returned by pointer subtraction and operator 'sizeof'
The compiler chooses some appropriate type for these. The library has
a typedef for that same type.
> * type_info (in <typeinfo>) returned by operator 'typeid'
The exact contents of class type_info are implementation-defined.
Furthermore, the way that a type_info object gets constructed by
(or in advance of) a call to typeid is also implementation-defined.
Obviously a compiler is free to implement this feature via run-time
code that gets linked into your program. Perhaps not so obviously,
that run-time support is not meant to be called directly from user
code. While the actual implementation technique for the run-time
library might be identical to the implementation techniques for the
standard library routines, that does not make the two libraries
identical.
[SNIP more examples]
> In my understanding, it is natural that library functions refer to and
> depend on other things defined in the library, but it's weird that some
> of the core language features also do. Moreover, in many implementations
> the core language is built into the compiler but the standard library is
> in the form of external files. There are several implementations of the
> standard library and one can even be replaced with another.
>
> How should I understand these? Please enlighten me on this matter.
The run-time library is part of the implementation of the compiler,
and the exact mechanisms need not be documented. By definition,
such routines are implementation-specific. If someone has a replacement
for the run-time library of one particular compiler, this does not mean
that other compilers are required to use discrete files for this purpose.
Recognizing the "layer" technique might be a good way to understand
how particular features are typically implemented, but since individual
compilers are allowed to implement the same feature differently, it's
important not to put too much stock in this.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kuyper@wizard.net ("James Russell Kuyper Jr.")
Date: Tue, 17 Sep 2002 12:01:14 +0000 (UTC) Raw View
Victor Bazarov wrote:
>=20
> "Martin v. L=F6wis" <loewis@informatik.hu-berlin.de> wrote...
....
> full steam ahead. Why do we still have to adhere to that? How
> many people would be affected _today_ if suddently "C compatibility"
> would be abandoned as a concept?
The fundamental problem is that, since things had to be defined that way
originally for reasons of C compatibility, there is now a fair amount of
C++ code that relies upon the same assumption. Therefore, "C
compatibility" issues become, with time, "C++ backwards compatibility"
issues. C++ is stuck with these problems essentially for all time. A
language that breaks free of these limitations will probably someday
replace C++ (that's the Java dream, for instance), but I don't think it
could properly be called C++.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kuyper@wizard.net ("James Russell Kuyper Jr.")
Date: Tue, 17 Sep 2002 12:01:34 +0000 (UTC) Raw View
Francis Glassborow wrote:
....
> functions cannot be written in C++. For example, malloc() is a function
> and so is part of the Standard Library but it cannot be written in C++.
It can't, in general, be written entirely in C++. However, on particular
platforms, it can be.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: loewis@informatik.hu-berlin.de (Martin v. =?iso-8859-1?q?L=F6wis?=)
Date: Tue, 17 Sep 2002 12:03:44 +0000 (UTC) Raw View
francis.glassborow@ntlworld.com (Francis Glassborow) writes:
> Well that is under your interpretation of operator. However The C++
> Standard lists sizeof as an operator and there are several other
> operators where you cannot write operator x()
Depends on where you look at. The section "Operators and Punctuators",
2.12, does not list sizeof. It is true that 5.3.3 calls it the "sizeof
operator".
> >- one could have made size_t a builtin type, with a keyword
> > and everything. That would have broken C compatibility.
>
> I do not see how that would be. For example wchar_t is a keyword for a
> fundamental type in C++ and just a typedef for an integer type in C.
And indeed, it does break C compatibility.
int main()
{
int wchar_t;
}
is well-formed in C, but ill-formed in C++.
> The writers of the Standard have much more freedom than you seem to
> think. And implementors have a pretty large amount as well.
If that is indeed so, then I should repeat the question of the OP: Why
did the standard authors chose to make the core language depend on the
library?
Regards,
Martin
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kuyper@wizard.net ("James Russell Kuyper Jr.")
Date: Tue, 17 Sep 2002 23:05:19 +0000 (UTC) Raw View
"Martin v. L=F6wis" wrote:
....
> Notice that neither sizeof nor typeid are "operators"; you can't write
> operator sizeof(foo). They are "special" expressions.
The standard calls both of them operators. See, for instance, 3.2p2,
which refers to the "sizeof operator" and the "typeid operator".
They are not overloadable operators (and that's a great relief - think
about it!). The list of things defined as 'operators' in 13.5p1 is not a
complete list of operators, it's actually only a list of the
overloadable operators, though it's not clearly identified as such.
You'll notice, for instance, that it contains none of the operators
listed in 13.5p3.
....
> Again, new and dynamic_cast are different: new is an operator,
> dynamic_cast is not.
5.2.7p1 refers to dynamic_cast as an operator.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kuyper@wizard.net ("James Russell Kuyper Jr.")
Date: Tue, 17 Sep 2002 23:05:28 +0000 (UTC) Raw View
Allan W wrote:
>
> musiphil@bawi.org (Sungbom Kim) wrote
> > My understanding of the relationship between the "core language" and the
> > "standard library" is that, though both constitute "the C++ Language",
> > the latter is a layer built on top of the layer of the former.
> > (Please correct me on this matter if I'm wrong.)
>
> An interesting way to categorize sections. Nothing in the standard says
> this, though (that I know of).
Section 1.5 p1:
"Clauses 2 through 16 describe the C++ programming language. ..."
p2:
"Clauses 17 through 27 (the _library clauses_) describe the Standard C++
library, ..."
The seperation between the language and the library is not complete;
this thread is a fairly accurate listing of features that cross that
boundary. However, for an entity as big and complicated as the C++
standard, that's a very small number of crossings of the boundary.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: francis.glassborow@ntlworld.com (Francis Glassborow)
Date: Tue, 17 Sep 2002 23:08:03 +0000 (UTC) Raw View
In article <j41y7tj8p6.fsf@informatik.hu-berlin.de>, Martin v. L=F6wis=20
<loewis@informatik.hu-berlin.de> writes
>int main()
>{
> int wchar_t;
>}
>
>is well-formed in C, but ill-formed in C++.
But it is still, IIRC, an error in C because wchar_t is reserved. It is=20
not only keywords that programmers must avoid. However that is hardly=20
relevant because I would be amazed if anyone actually used wchar_t as an=20
identifier. I would be equally amazed if anyone used size_t as an=20
identifier in C. We can overdo arguments about compatibility with C.
Actually my big objection to wchar_t being a fundamental type in C++ is=20
that it breaks the convention that '_t' notifies users that the name is=20
provided via a typedef. I would far have preferred C++ to create a new=20
fundamental type such as widechar and then have made wchar_t an alias=20
via a typedef and so have maintained consistency.
--=20
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: musiphil@bawi.org (Sungbom Kim)
Date: Sun, 15 Sep 2002 22:51:57 +0000 (UTC) Raw View
My understanding of the relationship between the "core language" and the
"standard library" is that, though both constitute "the C++ Language",
the latter is a layer built on top of the layer of the former.
(Please correct me on this matter if I'm wrong.)
But there are some things that contradict this understanding of mine;
some core language features seem to refer to and depend on the standard
library! They include (std:: qualifier omitted for brevity)
[normal types]
* ptrdiff_t, size_t (defined in <cstddef>)
returned by pointer subtraction and operator 'sizeof'
* type_info (in <typeinfo>) returned by operator 'typeid'
[exception types]
* bad_alloc (in <new>) thrown by operator 'new'
* bad_cast (in <typeinfo>) thrown by operator 'dynamic_cast'
* bad_typeid (in <typeinfo>) thrown by operator 'typeid'
* bad_exception (in <exception>) thrown by exception specification
[others]
* nothrow (in <new>) indicating that operator 'new' shouldn't throw
* uncaught_exception() (in <exception>) indicating whether
an exception has been thrown but hasn't yet been caught
* many other exception-related functions (in <exception>)
including unexpected(), terminate(), etc.
In my understanding, it is natural that library functions refer to and
depend on other things defined in the library, but it's weird that some
of the core language features also do. Moreover, in many implementations
the core language is built into the compiler but the standard library is
in the form of external files. There are several implementations of the
standard library and one can even be replaced with another.
How should I understand these? Please enlighten me on this matter.
--
Sungbom Kim <musiphil@bawi.org>
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: loewis@informatik.hu-berlin.de (Martin v. =?iso-8859-1?q?L=F6wis?=)
Date: Mon, 16 Sep 2002 15:33:22 +0000 (UTC) Raw View
musiphil@bawi.org (Sungbom Kim) writes:
> My understanding of the relationship between the "core language" and the
> "standard library" is that, though both constitute "the C++ Language",
> the latter is a layer built on top of the layer of the former.
> (Please correct me on this matter if I'm wrong.)
That, in general, is correct. As you point out yourself, if taken
strictly, it is not correct. Strictly speaking, there is just the C++
language.
> [normal types]
> * ptrdiff_t, size_t (defined in <cstddef>)
> returned by pointer subtraction and operator 'sizeof'
> * type_info (in <typeinfo>) returned by operator 'typeid'
Notice that neither sizeof nor typeid are "operators"; you can't write
operator sizeof(foo). They are "special" expressions.
>
> [exception types]
> * bad_alloc (in <new>) thrown by operator 'new'
> * bad_cast (in <typeinfo>) thrown by operator 'dynamic_cast'
Again, new and dynamic_cast are different: new is an operator,
dynamic_cast is not.
> [others]
Don't forget atexit, which interacts with global initializers. Also
don't forget the special position of the main function.
> In my understanding, it is natural that library functions refer to and
> depend on other things defined in the library, but it's weird that some
> of the core language features also do. Moreover, in many implementations
> the core language is built into the compiler but the standard library is
> in the form of external files. There are several implementations of the
> standard library and one can even be replaced with another.
No, they cannot be replaced; the compiler must know details of the
library, or else it cannot work correctly.
Notice that the standard defines the "free-standing" and the "hosted"
environment. The core language only refers to features required by a
free-standing environment. Everything that the "hosted" environment
adds (except for main) can indeed be implemented in a library, and
independently from the compiler.
> How should I understand these? Please enlighten me on this matter.
I think you are understanding these just fine: The core language
indeed refers to the library. In no case, this causes circularities
(in the sense that A is defined by using B and B is defined using A).
There is also no alternative for defining the language: It would have
been possible, but not feasible, to make all those aspects
"builtin". However, that would have had undesirable consequences:
- one could have made size_t a builtin type, with a keyword
and everything. That would have broken C compatibility.
- you could have made type_info builtin. Then there would be no way
to access it .name(), since builtin types don't have methods.
- I'm not sure how you could have avoided referring to the predefined
exceptions, unless you make those types also builtin - in which case
they would not have fit into the standard exception hierarchy.
Regards,
Martin
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: francis.glassborow@ntlworld.com (Francis Glassborow)
Date: Mon, 16 Sep 2002 16:44:52 +0000 (UTC) Raw View
In article <j4vg56nzr1.fsf@informatik.hu-berlin.de>, Martin v. L=F6wis=20
<loewis@informatik.hu-berlin.de> writes
>musiphil@bawi.org (Sungbom Kim) writes:
>
>> My understanding of the relationship between the "core language" and t=
he
>> "standard library" is that, though both constitute "the C++ Language",
>> the latter is a layer built on top of the layer of the former.
>> (Please correct me on this matter if I'm wrong.)
>
>That, in general, is correct. As you point out yourself, if taken
>strictly, it is not correct. Strictly speaking, there is just the C++
>language.
>
>> [normal types]
>> * ptrdiff_t, size_t (defined in <cstddef>)
>> returned by pointer subtraction and operator 'sizeof'
>> * type_info (in <typeinfo>) returned by operator 'typeid'
>
>Notice that neither sizeof nor typeid are "operators"; you can't write
>operator sizeof(foo). They are "special" expressions.
Well that is under your interpretation of operator. However The C++=20
Standard lists sizeof as an operator and there are several other=20
operators where you cannot write operator x() (I do not think you can=20
write operator.() nor operator::(). And typeid and the four new casts=20
are all listed as operators on page 120 of TC++PL 3ed. So I think you=20
have just defined the term in your own way.
>
>>
>> [exception types]
>> * bad_alloc (in <new>) thrown by operator 'new'
>> * bad_cast (in <typeinfo>) thrown by operator 'dynamic_cast'
>
>Again, new and dynamic_cast are different: new is an operator,
>dynamic_cast is not.
Depends which authority you look at. The Standard seems confused,=20
referring to some things as operators in one place and expressions in=20
another.
>
>> [others]
>
>Don't forget atexit, which interacts with global initializers. Also
>don't forget the special position of the main function.
>
>> How should I understand these? Please enlighten me on this matter.
>
>I think you are understanding these just fine: The core language
>indeed refers to the library. In no case, this causes circularities
>(in the sense that A is defined by using B and B is defined using A).
>
>There is also no alternative for defining the language: It would have
>been possible, but not feasible, to make all those aspects
>"builtin". However, that would have had undesirable consequences:
>- one could have made size_t a builtin type, with a keyword
> and everything. That would have broken C compatibility.
I do not see how that would be. For example wchar_t is a keyword for a=20
fundamental type in C++ and just a typedef for an integer type in C.
>- you could have made type_info builtin. Then there would be no way
> to access it .name(), since builtin types don't have methods.
We could have done whatever we wanted. Nowhere does it say that=20
fundamental types cannot have members. We chose to make some types=20
fundamental and provide some via the Standard C++ library. I think that=20
distinction can be exaggerated. I believe that, should they so choose,=20
implementors could provide type_info by any mechanism they like as long=20
as the semantics and syntax are as specified. I do not believe there has=20
to be a single line of source code to support such types.
>- I'm not sure how you could have avoided referring to the predefined
> exceptions, unless you make those types also builtin - in which case
> they would not have fit into the standard exception hierarchy.
The writers of the Standard have much more freedom than you seem to=20
think. And implementors have a pretty large amount as well.
--=20
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: francis.glassborow@ntlworld.com (Francis Glassborow)
Date: Mon, 16 Sep 2002 17:17:09 +0000 (UTC) Raw View
In article <3D82EE90.FB0248B8@bawi.org>, Sungbom Kim <musiphil@bawi.org>
writes
>In my understanding, it is natural that library functions refer to and
>depend on other things defined in the library, but it's weird that some
>of the core language features also do. Moreover, in many implementations
>the core language is built into the compiler but the standard library is
>in the form of external files. There are several implementations of the
>standard library and one can even be replaced with another.
There are two parts to the Standard Library. The first of these consists
of essential support for the core language. Some of these support
functions cannot be written in C++. For example, malloc() is a function
and so is part of the Standard Library but it cannot be written in C++.
It is an interface function between the language and the underlying
platform.
In addition, and implementation is permitted to know about the
implementation of its standard library. Such implementation can be done
by 'compiler magic' (i.e. my methods that are not available to the C++
programmer using just C++). For example, I believe that an implementor
can provide specialisations of complex for float, double and long double
that are implemented at assembler level (if I am wrong, and they cannot,
we need, IMHO, to revisit template rules so that they can)
One consequence is that standard library implementations are not fully
interchangeable. Furthermore, I think as library implementors get more
aggressive in optimising their products this will become increasingly
noticeable.
--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: vAbazarov@dAnai.com ("Victor Bazarov")
Date: Mon, 16 Sep 2002 17:22:14 +0000 (UTC) Raw View
"Martin v. L wis" <loewis@informatik.hu-berlin.de> wrote...
> [...]
> Notice that neither sizeof nor typeid are "operators"; you can't write
> operator sizeof(foo). They are "special" expressions.
You can't write
int a = 1, b = 2;
int c = operator +(a,b);
either. That doesn't make "+" a non-operator.
Besides, the Standard in 5.3.3/1 says "The sizeof OPERATOR ..."
(emphasis mine). So, according to the Standard, it _is_ an operator.
> [...]
> There is also no alternative for defining the language: It would have
> been possible, but not feasible, to make all those aspects
> "builtin". However, that would have had undesirable consequences:
> - one could have made size_t a builtin type, with a keyword
> and everything. That would have broken C compatibility.
Probably the biggest destructive force that prevent C++ from going
full steam ahead. Why do we still have to adhere to that? How
many people would be affected _today_ if suddently "C compatibility"
would be abandoned as a concept?
> - you could have made type_info builtin. Then there would be no way
> to access it .name(), since builtin types don't have methods.
That is in no way a requirement. Fundamental types don't have
member functions because they don't, not because they can't.
Just like 'operator new' can be an implicitly declared function,
the language has nothing that would prevent implicit definition
of classes (which would be called "built-in" in that case).
> - I'm not sure how you could have avoided referring to the predefined
> exceptions, unless you make those types also builtin - in which case
> they would not have fit into the standard exception hierarchy.
Why wouldn't they? Make std::exception implicitly defined and
some other classes can be made implicitly defined as well. What
would be wrong with it?
Victor
--
Please remove capital A's from my address when replying by mail
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]