Browse files

[GH #832] Probe for broken snprintf %+..u in mingw and fix it.

snprintf %+u fails on mingw only. t/op/sprintf.t test 217 and
t/op/string.t: 196, 198 (now 197)
The + is always printed, but should not.

As it works okay in win32 (with msvcrt.ll) and cygwin (cygwin1.dll)
on the same system, I assumed it's mingw only snprintf/sprintf wrapper
issue.

Probe in auto:snprintf for PARROT_HAS_BROKEN_SPRINTF_UPLUS and skip
the '+' in %+..u in spf_render.c.

But the probe is not yet correct. It passes on mingw, but should fail.
  • Loading branch information...
1 parent 169598d commit 1e44cc13774e254f234930c0447f0e2268c26a9f @rurban rurban committed Sep 17, 2012
Showing with 78 additions and 6 deletions.
  1. +32 −4 config/auto/snprintf.pm
  2. +16 −2 config/auto/snprintf/test_c.in
  3. +16 −0 config/gen/config_h/feature_h.in
  4. +14 −0 src/string/spf_render.c
View
36 config/auto/snprintf.pm
@@ -1,13 +1,15 @@
-# Copyright (C) 2001-2009, Parrot Foundation.
+# Copyright (C) 2001-2012, Parrot Foundation.
=head1 NAME
-config/auto/snprintf.pm - Test for snprintf
+config/auto/snprintf.pm - Test for snprintf and %+u
=head1 DESCRIPTION
Tests if snprintf is present and if it's C99 compliant.
+Also tests for broken %+u on mingw
+
=cut
package auto::snprintf;
@@ -20,7 +22,7 @@ use base qw(Parrot::Configure::Step);
sub _init {
my $self = shift;
my %data;
- $data{description} = q{Test snprintf};
+ $data{description} = q{Test snprintf and %+u};
$data{result} = q{};
return \%data;
}
@@ -29,9 +31,11 @@ sub runstep {
my ( $self, $conf ) = @_;
my $res = _probe_for_snprintf($conf);
-
$self->_evaluate_snprintf($conf, $res);
+ $res = _probe_for_broken_uplus($conf);
+ $self->_evaluate_broken_uplus($conf, $res);
+
return 1;
}
@@ -44,6 +48,16 @@ sub _probe_for_snprintf {
return $res;
}
+sub _probe_for_broken_uplus {
+ my $conf = shift;
+ $conf->cc_gen('config/auto/snprintf/test_c.in');
+ my $has_snprintf = $conf->data->get('HAS_SNPRINTF');
+ $conf->cc_build('-DBROKEN_SPRINTF_UPLUS ' . ($has_snprintf ? ' -DHAS_SNPRINTF' : ''));
+ my $res = $conf->cc_run() or die "Can't run the snprintf testing program: $!";
+ $conf->cc_clean();
+ return $res;
+}
+
sub _evaluate_snprintf {
my ($self, $conf, $res) = @_;
if ( $res =~ /snprintf/ ) {
@@ -59,6 +73,20 @@ sub _evaluate_snprintf {
return 1;
}
+sub _evaluate_broken_uplus {
+ my ($self, $conf, $res) = @_;
+ if ( $res =~ /^not ok/ ) {
+ $conf->data->set( HAS_BROKEN_SPRINTF_UPLUS => 1 );
+ }
+ elsif ( $res =~ /^ok/ ) {
+ return 1;
+ }
+ else {
+ die "\nConfigure.pl: probe_for_broken_uplus failed\n";
+ }
+ return 1;
+}
+
1;
# Local Variables:
View
18 config/auto/snprintf/test_c.in
@@ -1,5 +1,5 @@
/*
-Copyright (C) 2004-2009, Parrot Foundation.
+Copyright (C) 2004-2012, Parrot Foundation.
*/
@@ -14,13 +14,27 @@ main(int argc, char* argv[])
char buf[10];
int n;
+#ifdef BROKEN_SPRINTF_UPLUS
+# ifdef HAS_SNPRINTF
+ snprintf(buf, 10, "%+u", 123);
+# else
+ sprintf(buf, "%+u", 123);
+# endif
+ if (*buf == '+')
+ puts("not ok");
+ else if (*buf == '1')
+ puts("ok");
+ else
+ puts("unknown");
+#else
n = snprintf(buf, 2, "%s", "01234");
if (n == -1)
puts("old snprintf");
else if (n == 5)
puts("C99 snprintf");
else
- printf("borken snprintf: n = %d\n", n);
+ printf("broken snprintf: n = %d\n", n);
+#endif
return 0;
}
View
16 config/gen/config_h/feature_h.in
@@ -175,6 +175,22 @@ END_PRINT
print OUT <<'END_PRINT';
+/* from config/auto/snprintf */
+END_PRINT
+if (@HAS_BROKEN_SPRINTF_UPLUS@) {
+ print OUT <<'END_PRINT';
+/* mingw */
+#define PARROT_HAS_BROKEN_SPRINTF_UPLUS 1
+END_PRINT
+}
+else {
+ print OUT <<'END_PRINT';
+#undef PARROT_HAS_BROKEN_SPRINTF_UPLUS
+END_PRINT
+}
+
+print OUT <<'END_PRINT';
+
#endif /* PARROT_FEATURE_H_GUARD */
END_PRINT
View
14 src/string/spf_render.c
@@ -427,6 +427,9 @@ Parrot_sprintf_format(PARROT_INTERP, ARGIN(const STRING *pat), ARGMOD(SPRINTF_OB
SpfInfo info = { 0, 0, 0, 0, (PHASE)0 }; /* Storage for flags, etc. */
PMC * const targ = Parrot_pmc_new_init_int(interp, enum_class_StringBuilder, pat_len * 2);
INTVAL fmt_start_idx;
+#ifdef PARROT_HAS_BROKEN_SPRINTF_UPLUS
+ INTVAL plus = -1; /* index for '+' to skip on mingw */
+#endif
/* ts is used almost universally as an intermediate target;
* tc is used as a temporary buffer by Parrot_str_from_uint and
@@ -566,6 +569,9 @@ Parrot_sprintf_format(PARROT_INTERP, ARGIN(const STRING *pat), ARGMOD(SPRINTF_OB
case '+':
info.flags |= FLAG_PLUS;
+#ifdef PARROT_BROKEN_SPRINTF_PLUS
+ plus = i;
+#endif
continue;
case '0':
@@ -774,6 +780,14 @@ Parrot_sprintf_format(PARROT_INTERP, ARGIN(const STRING *pat), ARGMOD(SPRINTF_OB
const UHUGEINTVAL theuint =
obj->getuint(interp, info.type, obj);
sharedint = theuint;
+#ifdef PARROT_HAS_BROKEN_SPRINTF_UPLUS
+ if ((info.flags & FLAG_PLUS) && (plus > -1)) { /* [GH #832] mingw */
+ pat = Parrot_str_concat(interp, STRING_substr(interp, pat, 0, plus),
+ STRING_substr(interp, pat, plus+1, pat_len));
+ pat_len--;
+ i--;
+ }
+#endif
}
goto do_sprintf;
case 'd':

0 comments on commit 1e44cc1

Please sign in to comment.