Austin Group Defect Tracker

Aardvark Mark IV


Viewing Issue Simple Details Jump to Notes ] Issue History ] Print ]
ID Category Severity Type Date Submitted Last Update
0001558 [1003.1(2016/18)/Issue7+TC2] Shell and Utilities Objection Enhancement Request 2022-01-24 08:51 2022-04-07 16:06
Reporter stephane View Status public  
Assigned To
Priority normal Resolution Rejected  
Status Closed  
Name Stephane Chazelas
Organization
User Reference
Section 2.13.1 Patterns Matching a Single Character
Page Number 2383
Line Number 76228
Interp Status ---
Final Accepted Text
Summary 0001558: require [^...] in addition to [!...] for bracket expression negation
Description (page/line numbers above are from Draft 2.1)

There's a very unfortunate difference between sh/fnmatch globs and regexps in that [^...] is used in regexps (and most other places/languages) and [!...] in sh/fnmatch wildcard patterns (and [~...] in rc/es though that's not relevant here).

The only reason is that the Bourne shell had decided to keep ^ as a pipe operator for backward compatibility with the Thompson shell, and since it's not an error there to have [ / ] unmatched, ^ could not be used as negation operator inside bracket expressions.

But POSIX sh it not and is not compatible with the Bourne shell and POSIX does not allow ^ be treated specially, and leaves [^...] unspecified, more or less explicitly allowing ^ to be used as negation there and it's been the case for decades. Most sh/fnmatch implementations have now moved on and allow [^...] for negation.

Among common sh implementations, the only exceptions that I know are ksh88 (and pdksh and derivatives) and bosh (that one still treats ^ as a pipe operator except with -o posix).

All of bash, zsh, yash, dash, BSDs (except those like OpenBSD, MirBSD that use pdksh) allow [^...]. Most fnmatch() implementations do (including on OpenBSD making it a discrepancy between sh and fnmatch()/find...).
Desired Action Require [^...] to negate the bracket expression in addition to [!...] in issue8, or at least make it a "future direction" that it *will* be required in a future version, so as to at last remove that unnecessary discrepancy between regexp and shell pattern syntax.

[!...] would have to be retained for backward compatibility (making it a remaining difference with regexps). [\^!] and [\!^] can both be used to match either ^ or ! (ksh93 is not compliant to that atm but it looks like it's the only one).
Tags No tags attached.
Attached Files

- Relationships

-  Notes
(0005637)
mirabilos (reporter)
2022-01-28 11:27

Objection.

This will break scripts that currently use [^something], and I have seen multiple scripts doing so. They specifically rely on the fact that ^ in shell globs is not the same as ! in shell globs or ^ in REs.
(0005638)
stephane (reporter)
2022-01-28 17:15

Re: Note: 0005637
> This will break scripts that currently use [^something], and I have seen multiple scripts doing so. They specifically rely on the fact that ^ in shell globs is not the same as ! in shell globs or ^ in REs

Those scripts are already not POSIX compliant. POSIXly currently leaves it unspecified what [^x] matches. [x^] or [\^x] should be used instead in POSIX sh scripts or fnmatch() invocations.

If mksh currently documents that [^x] is guaranteed to match on ^ and x, you could make the change only in POSIX mode.
(0005640)
mirabilos (reporter)
2022-01-30 19:22

It is unspecified because shells have historically differed, and because the standard allows for them to do so.

Why do you want to break these things now? I don’t go and request things to change from unspecified to mksh’s behaviour where I know other major shells differ either.
(0005641)
Don Cragun (manager)
2022-01-30 20:09

The page and line numbers have been updated to match the project. The page and line numbers originally referred to the issue 8 draft project draft 2.1.
(0005642)
oguzismailuysal (reporter)
2022-01-31 06:11

I don't see what this change is going to achieve other than compelling other developers to adopt your shell's behavior.
(0005643)
calestyo (reporter)
2022-01-31 22:06

Just a general word:

I can see why people from shells that behave in another way are not very keen on "resolving" such things (regardless of from which "side" one is looking).

But in the end one should also not forget that with such incompatibilities, typically everyone looses, as scripts from any "side" cannot reliably be use with other implementations.

So I think there would be in fact *some* benefit on resolving such things.


As things are, such script are already not portable... and no implementation would be forced to adapt any change in the standard (so there wouldn't have to be any breakage).
But it could be a long-term path towards getting better portability.
(0005644)
mirabilos (reporter)
2022-02-01 19:27

On the other hand, in scripts that aren’t already portable, using those is no big loss.

I’d not want to make this dependent on the -o posix flag. Consistent behaviour is better (and uses less code). (And the glob implementation is surprisingly tricky.)

Another thing is user scripts. Do you have any IDEA of how HARD it is to figure out which scripts may be affected?

I’m trying a recursive grep excluding *.{c,h,pl} but all those shell scripts call sed, configure calls expr, etc. and I have *TONS* of [^…] to review.

No, I’m sticking to my objection to making the standard require the behaviour of an arbitrary other shell, *ESPECIALLY* as the shown workaround doesn’t even work with the (AT&T) Korn Shell.
(0005646)
calestyo (reporter)
2022-02-01 19:42

Sure, but there's no win or improvement either. Things just remain non-portable.

The only difference is that even more people may use such non-portable features, given that there's not even a long-term path to phase them out.


It wouldn't be the behaviour of an arbitrary shell in this specific case - it would be aligning the syntax of patter matching notation to that of REs.

But still, I can fully understand your reason for objecting.
(0005663)
mirabilos (reporter)
2022-02-06 11:22

“Things just remain non-portable.”

That’s a not-loss, but it has a win (things that currently work with a given shell stay working).

The alternative would be worse (especially for users), especially with this being *utterly* hard to find in scripts with tools like grep, as scripts *also* use BRE in sed etc. a lot.

Why would you even *want* to “align[] the syntax of patter[n] matching notation to that of REs”? The question mark and asterisk already are hugely different, as is the anchoring behaviour. I’d argue that less similarity might even be better here.
(0005677)
mirabilos (reporter)
2022-02-17 23:46

It gets worse.

Expecting my objection here to be ignored, I’ve added debugging code to mksh (and, indeed, adding the caret needs changes in more than one codepath, and it’s very much something I’d like to not need to do because more checks make the code slower), and it triggers a warning on:

[…]
# Sed expression to map a string onto a valid CPP name.
as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
[…]
echo moo | $as_tr_cpp

This is what GNU autoconf does by default.

W: configure[557]: unescaped [^...] in shellglob; this may change the meaning in the future!

So, well, why? Because the variable contains…

typeset as_tr_cpp='eval sed '\''y%*abcdefghijklmnopqrstuvwxyz%PABCDEFGHIJKLMNOPQRSTUVWXYZ%;s%[^_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]%_%g'\'

(via “typeset -p”), and without -o noglob, using it as simply $as_tr_cpp does, in fact, glob on it.

Yes, clearly a bug in GNU autoconf… which I’m not personally going to even try and report. The …[^… is passed to sed. But it is also processed by the shell first, by accident. (This is from OpenSSH-portable’s configure.)

This just shows, again, just how *hard* it’ll be to debug these things…

Please rescind the change request, keep [^…] as it currently is, then I need not bother with these shenaningans to warn *my* current users. Also do consider that it’s *currently* listed as “unspecified results”, and the XBD Conformance makes me think that it is very much alright if an implementation chooses to do something there, just that a conforming application must live with it (as opposed to “undefined”).
(0005678)
Don Cragun (manager)
2022-02-18 04:04

Withdrawn at the request of the submitter in Note: 0005677.
(0005679)
Don Cragun (manager)
2022-02-18 05:04

I mistakenly thought that mirabilos was the person who submitted this enhancement request. This bug has been reopened.
(0005685)
zackw (reporter)
2022-02-18 15:59
edited on: 2022-02-18 16:00

I am one of the maintainers of Autoconf; mirabilos' report above was brought to my attention by Eric Blake.

The "as_tr_cpp" construct mirabilos found is indeed a bug in Autoconf, and one which could potentially bite _regardless_ of whether [^...] is interpreted as a complemented range in shell globbing. It is, after all, a glob pattern either way. Autoconf has hitherto gotten away with it because it's very unlikely that anyone would run a generated configure script in a directory containing a file that actually matches the glob, or with (an equivalent of) Bash's 'nullglob' or 'failglob' modes enabled, but I've still added it to our list of bugs to be fixed eventually. (We're very understaffed right now and in any case it will take a long time for the fix to trickle out to the deployed base of configure scripts.)

Anyhow, I agree with mirabilos; POSIX should not make this change. Since there already exist both shells that treat [^...] as a complemented range, and shells that don't, and since [!...] would have to be preserved for compatibility, and since it takes _decades_ for changes to the POSIX shell spec to become ubiquitously available[*], adding a mandate for [^...] complemented glob ranges doesn't actually make it easier to write portable shell scripts. POSIX should just leave bad enough alone.

[*] In case any readers were not aware of this, people still regularly expect Autoconf's 'config.guess' helper script to work with shells that don't implement $(...) or user-defined functions.

(0005690)
calestyo (reporter)
2022-02-19 01:03

Not that I'd have a very strong opinion on this,... but I still don't quite get what people fear here:

- Shells already do use [^...] in one way or the other, thereby making script non-portable as soon as sides are switched (or are there any shell that just fail with an error if they encounter it?).
So possible breakage is already there if people use this feature. If they don't use (which they shouldn't anyway) no implementation of either side would suffer.

- Any shell that handles [^...] in one way or the other, could just continue to do so, regardless of what POSIX says. If a shell thinks that all it's users use only scripts that handles this in either way - fine... just go on with that.

- Whether or not POSIX would change anything with respect to that (and if it would be just a "future direction")... shells handling it in one way could eventually still end up being compelled to adapt, namely if a majority of shell implementations (or actually: shell scripts) simply use it in the other way... and a shell sees more and more issues, with scripts taken from the other "side".


Doing nothing just means, that things like that issue in autoconf will keep popping up forever. Doing something could at least give a (very) long term path to clean things up.

Shells could e.g. just give a warning, that this feature is non-portable and may be removed/changed in some decades.
(0005691)
kre (reporter)
2022-02-19 09:28

Re Note: 0005690

    Doing nothing just means, that things like that issue in autoconf will keep
    popping up forever.

That issue (bug) has nothing whatever to the change requested here, and would
be a bug whatever the rules are for negating char classes in glob patterns.
It was (is) a simple quoting error.

FWIW I disagree with this proposed change - not necessarily with its objective,
but with the use of the standards process to attempt to force implementations
to change. The correct way to make this happen, if it were to be possible,
would be to convince the shell implementers to make it happen, as being a
desirable outcome for the community - not to attempt to force them to by
making it a requirement of the standard.

It is clear from the current wording, that this issue has been considered
before, and it was discovered that there is no common behaviour that can be
standardised. Hence, unspecified. Applications must avoid using ^ as the
first char of a glob char class, as what the implementation will do with that
isn't consistent. If there is a desire to make the world a better place,
get that message out to the users.

If we can get users/scripts to stop using ^ as the first char in a char
class, then the implementations would no longer need to support it, and
we might eventually be able to get rid of the "there are two ways you can..."
nonsense, when there's no good reason for having two. Using ! for this
purpose is entrenched in glob,. from well before the Bourne shell (regardless
of whether or not ^ might still have been being retained for pipes). There
is no way to make that one go away, so if we were to simplify things,
making it clear that in a glob char class, ^ is simply a character, and
has no special meaning wherever placed, would be the way to go. We cannot
do that as too many shells don't implement it that way however.

Note that the "symmetry with regular expressions" argument is absurd, aside
from both being a form of pattern matching, glob expressions and regular
expressions have almost nothing in common - there's no particular reason that
character classes should be an exception to that.

For now, all the standard can do is leave this unspecified.
(0005692)
stephane (reporter)
2022-02-19 18:16

Wow! I didn't expect such a barrage of objections!

Of those, the one that makes most sense to me is kre's (the
maintainer of NetBSD sh) to say implementations should be
fixed first (in Note: 0005691 above). But I'd argue they have
already for the most part.

When, 30 years ago, POSIX forbade ^ to be treated as a pipe
operator like it was in the Bourne shell, and left [^x]
unspecified, I think it was a clear sign for implementers
that they could use [^x] as a negation operator and remove
that non-sensical discrepancy with regexps and other
shells/languages.

And most did.

Most shells and most fnmatch() / glob() implementations
understand [^x]. Many shells/libcs implementations started
off understanding [^x] from the start (and [!x] as well for
SysV compatibility or POSIX compliance), on some systems, it
changed later.

You can see BSD fnmatch() added support for [^x] in addition
to [!x] circa 1994 with a comment that acknowledges that
it's allowed by POSIX.

FreeBSD sh added [^x] as an alias to [!x] in 1997, NetBSD
shortly after (of course the BSD shell, csh always had [^x]
and not [!x] as it was not encumbered with Thompson shell
backward compatibility).

dash now uses the libc's fnmatch() (which on most systems
understand [^x] (the few remaining SysV based ones may be
exceptions but I don't have access to any to test on).

ksh (on which the POSIX sh spec is based) added it in 2005
(see RELEASE file in libast there) in ksh93r (the release
notes of the shell itself don't even mention it).

yash, which was written to the standard, understood [^x] and
[!x] from the start.

The only actively maintained shells that I know don't
support [^x] as negation are the ones based on pdksh:
OpenBSD's ksh and MirBSD ksh (mksh, also found on Android),
even though on those systems fnmatch() does support [^x].

In mksh, [^x] was matching on ^ and x but mirabilos has
*already* introduced code to warn against that usage
following this bug. The current version as found on Debian
has:

$ mksh -c 'case a in [^a]) echo x; esac'
W: mksh: unescaped [^...] in shellglob; this may change the meaning in the future!
x

Which means you can already no longer use that non-standard
extension (whereby [^x] matches on ^ and x) in that shell.

Solaris' /usr/xpg4/bin/sh, based on ksh88i is also affected,
but I wouldn't call it "actively maintained" as it has many
well known major bugs and POSIX non-compliances that have
been well known for long and never fixed. Also /bin/sh on
Solaris changed from the Bourne shell to ksh93, and the
addition of [^x] support must have been the most minor of
the incompatibilities it introduced there (and that /bin/sh is
more POSIX compliant than /usr/xpg4/bin/sh even if it's the
latter that was certified so I don't expect /usr/xpg4/bin/sh
has much of a future).

And to clarify: I'm not the maintainer of any shell (though
I've contributed patches to several on either side of this
divide), nor of any libc (or any software of any
significance to POSIX for that matters). I've been answering
shell-related questions on usenet and unix.stackexchange.com
for over 25 years. Over these years, I've been painstakingly
telling people in Bourne-like shell or find -name patterns,
you can't use [^x] portably, that POSIX leaves it
unspecified, you should use [!x] instead, and often they
don't believe you or don't care as most implementations
support [^x] as well.

I'm thinking with issue8 coming out soon, it's a good
opportunity to nudge the remaining few implementations in the
right direction with at least a "future direction" that says
that [^x] may be required to be treated the same as [!x] in
future versions of the standard.

From the comments on this bug, I'm under the impression that
not all people realise that POSIX already allows them to do
so, that code such as echo [^x] or case x in [^x]) is not
valid POSIX sh code, and that the change I suggest here is
to make it valid code with behaviour that matches that of
the great majority of implementations.
(0005693)
hvd (reporter)
2022-02-19 18:44

> dash now uses the libc's fnmatch() (which on most systems
> understand [^x] (the few remaining SysV based ones may be
> exceptions but I don't have access to any to test on).

This is incorrect. Whether dash uses the libc's fnmatch is configurable. When fnmatch is not used, ^ is always taken as a literal. When fnmatch is used, dash's current behaviour is buggy and the maintainer's proposed fix is to always escape ^ before passing it to fnmatch, forcing it to be taken as a literal regardless of how libc's fnmatch behaves.

> From the comments on this bug, I'm under the impression that
> not all people realise that POSIX already allows them to do
> so, that code such as echo [^x] or case x in [^x]) is not
> valid POSIX sh code

It appears to me that everyone here is well aware of that. It may not be valid POSIX sh code, but it may well be valid code for particular implementations of sh, and changing POSIX would either force those shells to implement separate POSIX and non-POSIX modes, or break existing scripts written for those shells.
(0005694)
calestyo (reporter)
2022-02-19 18:57

>When fnmatch is used, dash's current behaviour
>is buggy and the maintainer's proposed fix is to
>always escape ^ before passing it to fnmatch,
>forcing it to be taken as a literal regardless
>of how libc's fnmatch behaves.

Wasn't that because of the bug I've found when ^ *is* quoted?
Did the maintainer actively decide for this behaviour,... or is it now just a consequence of the other fix?
(0005695)
zackw (reporter)
2022-02-19 19:16
edited on: 2022-02-19 19:16

I would like to clarify that my objection is based strictly on the observation that old shells never die. Solaris sh may be full of well-known bugs and noncompliances, but it's still widely used, and people objected immediately the last time the Autotools suite tried to desupport it (see e.g. https://lists.gnu.org/archive/html/config-patches/2021-05/msg00000.html [^] ). I fully expect it to outlive me. In a similar way, I don't expect it will *ever* in my lifetime be safe for Autoconf scripts to use `[^...]` as a complemented range in globs, and therefore I don't see any real value in making the spec require it to be a complemented range.

Autoconf may seem like an outlier in its portability needs, but here's the thing: If portability to the entire clade of Unixes isn't your priority, *why are you writing a shell script?* There are much better scripting languages nowadays; the fact that you can count on /bin/sh to exist *everywhere* is the only thing shell has going for it anymore.

Because of that I'm -0.5 on *any* change to the shell spec. Let it be what it is, warts and all; instead put development effort into those better scripting languages.

(0005696)
hvd (reporter)
2022-02-19 23:26
edited on: 2022-02-19 23:27

> Wasn't that because of the bug I've found when ^ *is* quoted?
> Did the maintainer actively decide for this behaviour,... or is it now just a consequence of the other fix?

Yes, the maintainer actively decided for this behaviour, to have consistency between fnmatch and non-fnmatch builds. The change to just fix quoted ^ and have unquoted ^ behave however libc decides was literally two one-character changes, the maintainer came up with a larger change to always escape ^ with the reasoning:

> > However, whether this is the correct approach is a matter of opinion:
> > dash could alternatively choose to always take ^ as a literal and always
> > escape it before passing it on to fnmatch(), overriding whatever
> > decision the libc people had taken.
>
> Yes, this would produce the most consistent result.

(0005720)
mirabilos (reporter)
2022-02-25 21:10

“In mksh, [^x] was matching on ^ and x but mirabilos has
*already* introduced code to warn against that usage
[…]
Which means you can already no longer use that non-standard”

No.

It means the shell now warns about it, *because* of this bad bad bad change request. That is a highly experimental change in an unstable development preview.

The warning is clearly a bad idea, and I’ll need to at least mask it if -o posix is in effect (for autoconf).

I would *very* much to remove the warning, and the complicated code that enables it (and too often, at that), again.

In fact, I’m very much in favour of the recommendation of requiring ^ to be a regular character in glob character classes (i.e. the way mksh does it), but I’ll gladly settle with continuing to keep it unspecified. Scripts specifically targetting mksh may then rely on it being a regular character (which they need to do for ksh93 apparently anyway as \^ reportedly doesn’t work there).

I *am* the maintainer of a shell, and one with several billion(!) installations (mostly thanks to Android). I’m also an avid shell script programmer, and I know I *have* seen scripts using [^…] as nōn-negation AND I CANNOT FIND THEM NOW because grepping is futile (scripts use [^…] with sed, expr, etc. all the time).

I’d be *very* annoyed if a future standard *deliberately* requires an existing implementation with a 36 year or so history (pdsh → pdksh → oksh → mksh) to change this.

I’m also a bit wary how you (Stéphane) seem to not do your shellology right, putting things into one basket that are clearly separate and misresearching dash on top.

「It may not be
valid POSIX sh code, but it may well be valid code for particular
implementations of sh, and changing POSIX would either force those shells
to implement separate POSIX and non-POSIX modes, or break existing scripts
written for those shells.」

This is *exactly* why I’m objecting to this.

「I would like to clarify that my objection is based strictly on the
observation that old shells never die. Solaris sh may be full of」

This is *also* a very valid point. In writing mksh’s Build.sh script I’m encountering the same (although I did draw the line at shells that don’t have functions). The autoconf texinfo documentation is a goddess-sent for that (thanks zackw and contributors)!

「instead put development effort into those better scripting languages. 」

I’m trying to make mksh one of those better scripting languages ☻

(Nice to see that dash also argues with consistent results.)
(0005728)
calestyo (reporter)
2022-03-03 03:26

"I would like to clarify that my objection is based strictly on the
observation that old shells never die."

=> so what? they never need to adapt (and likely never will), and if they get any scripts from either side of other implementations they'd anyway fail or succeed already.


"recommendation of requiring ^ to be a regular character in glob character classes"

=> That seems IMO worse than requiring it to negate.

My personal motivation on why I'd prefer to see this standardised in one way or the other is simply that shells do already handle this incompatible, and people use it... I guess quite often without even realising that this is non-portable.

The only reason why I'd slightly prefer ^ to mean negation is simply for alignment with REs.

But if it wouldn't cause any issues - which however you indicate it would - I'd even prefer if shells just give a warning that this is non-portable when its used... and specifying neither of the two sides (negation vs. literal), rather than specifying ^ to be literal, which would also break "one side" AND be unaligned with REs.
(0005733)
zackw (reporter)
2022-03-04 02:38

>> old shells never die
> so what?

So portable shell scripts can never rely on _any_ of the three possible behaviors. Since one always has better options than shell script if one doesn't need portability, the proposed change is pointless.

Yes, this logic applies to all possible changes to the shell spec. As far as I'm concerned, the shell language should be frozen and abandoned.
(0005785)
Don Cragun (manager)
2022-04-07 16:06

This bug is rejected because there is no consensus to make the requested change.

- Issue History
Date Modified Username Field Change
2022-01-24 08:51 stephane New Issue
2022-01-24 08:51 stephane Name => Stephane Chazelas
2022-01-24 08:51 stephane Section => 2.13.1 Patterns Matching a Single Character
2022-01-24 08:51 stephane Page Number => 2352
2022-01-24 08:51 stephane Line Number => 76144
2022-01-24 13:51 calestyo Issue Monitored: calestyo
2022-01-28 11:27 mirabilos Note Added: 0005637
2022-01-28 17:15 stephane Note Added: 0005638
2022-01-30 19:22 mirabilos Note Added: 0005640
2022-01-30 20:09 Don Cragun Page Number 2352 => 2383
2022-01-30 20:09 Don Cragun Line Number 76144 => 76228
2022-01-30 20:09 Don Cragun Interp Status => ---
2022-01-30 20:09 Don Cragun Note Added: 0005641
2022-01-31 06:11 oguzismailuysal Note Added: 0005642
2022-01-31 22:06 calestyo Note Added: 0005643
2022-02-01 19:27 mirabilos Note Added: 0005644
2022-02-01 19:42 calestyo Note Added: 0005646
2022-02-06 11:22 mirabilos Note Added: 0005663
2022-02-17 23:46 mirabilos Note Added: 0005677
2022-02-18 04:04 Don Cragun Note Added: 0005678
2022-02-18 04:04 Don Cragun Status New => Closed
2022-02-18 04:04 Don Cragun Resolution Open => Withdrawn
2022-02-18 05:04 Don Cragun Note Added: 0005679
2022-02-18 05:04 Don Cragun Status Closed => New
2022-02-18 05:04 Don Cragun Resolution Withdrawn => Open
2022-02-18 15:59 zackw Note Added: 0005685
2022-02-18 16:00 zackw Note Edited: 0005685
2022-02-19 01:03 calestyo Note Added: 0005690
2022-02-19 09:28 kre Note Added: 0005691
2022-02-19 18:16 stephane Note Added: 0005692
2022-02-19 18:44 hvd Note Added: 0005693
2022-02-19 18:57 calestyo Note Added: 0005694
2022-02-19 19:16 zackw Note Added: 0005695
2022-02-19 19:16 zackw Note Edited: 0005695
2022-02-19 23:26 hvd Note Added: 0005696
2022-02-19 23:27 hvd Note Edited: 0005696
2022-02-25 21:10 mirabilos Note Added: 0005720
2022-03-03 03:26 calestyo Note Added: 0005728
2022-03-04 02:38 zackw Note Added: 0005733
2022-04-07 16:06 Don Cragun Note Added: 0005785
2022-04-07 16:06 Don Cragun Status New => Closed
2022-04-07 16:06 Don Cragun Resolution Open => Rejected


Mantis 1.1.6[^]
Copyright © 2000 - 2008 Mantis Group
Powered by Mantis Bugtracker