Skip to content

Commit

Permalink
This is that huge sprintf thing I've been working on all week.
Browse files Browse the repository at this point in the history
One possible problem: Sun's compiler seems to continually complain about our
varargs accesses.  I don't know if the current approach will work correctly, but
I suspect it will.

From one of the announcement e-mails:

***

First of all, it completes the feature set of the Parrot_sprintf family, including
width and precision for ints and strings.  It also makes handling of strings and
floats safe.  Further, it changes the old %P format (PMC) to a new P size--%Ps,
%Pd, %Pf, etc.  It fixes the problem with HUGEINTVAL by auto-detecting it at
compile time.  (If you compile Parrot on a machine that supports long long, %Hd
will format one; same with long double and %Hg.)

It adds PIO_printf, PIO_eprintf (error printf) and PIO_fprintf.  The first two
default to stdio if there's no interpreter available.

It modifies the Parrot_warn family and PANIC to use PIO_eprintf.  It modifies
every file that has access to PIO (in other words, anything that includes
parrot.h) to use PIO_printf and PIO_eprintf.

It slightly modifies conversions between STRINGs and FLOATVALs, using %g instead
of %f.

***

And the other one:

***

Inspiration struck me as I was working on bug fixes for Parrot_sprintf's patch
yesterday.  One of my long-term goals with Parrot_sprintf was to use it as the
engine for a Parrot bytecode-level sprintf opcode, but I didn't think that would
be possible without duplicating the code in two different files with different
versions of the same macros wrapping accesses to the arglist.  Obviously, this is
a Bad Thing, so I just let my mind crunch on it a while.

Until today, when I realized the solution that had been staring me in the face all
along.

The answer was vtables.  A specialized vtable wrapping argument accesses would
mean one version of the formatting code, but two different behaviors!  Excited, I
set to rewriting Parrot_sprintf--*again*--to use this idea.

Along the way, %S went the way of %P (you should now use %Ss to insert a STRING*,
but %S will still work), two new opcodes got added, and I managed to remove
several restrictions on strings that I had imposed on myself by using C strings
internally instead of Parrot ones.  The result (I hope) is better, faster, and
stronger than the original.

When misc.c reached around a thousand lines, I decided it was becoming
unmanageable, so I split misc.c into three files.  Misc.c contains the public
"wrapper" functions around the core formatter, spf_render.c contains the
formatter and some utility functions, and spf_vtable.c contains the two vtables
used to make Parrot_sprintf work.

***

Includes an expanded test suite in t/src/sprintf.t and another test in
t/op/string.t.  All tests pass on Cygwin and Win32, 'cept t/src on Win32, which
didn't work in the first place.


git-svn-id: https://svn.parrot.org/parrot/trunk@2372 d31e2699-5ff4-0310-a27c-f18f2fbe73fe
  • Loading branch information
brentdax committed Oct 11, 2002
1 parent 02c63c7 commit 53b5369
Show file tree
Hide file tree
Showing 51 changed files with 3,327 additions and 1,725 deletions.
2 changes: 2 additions & 0 deletions MANIFEST
Expand Up @@ -585,6 +585,8 @@ rx.c
rx.ops
rxstacks.c
smallobject.c
spf_render.c
spf_vtable.c
stacks.c
string.c
sub.c
Expand Down
62 changes: 62 additions & 0 deletions config/auto/sizes.pl
Expand Up @@ -41,6 +41,68 @@ sub runstep {
still compile and run, but you may see a ton of warnings.
END
}

#Get HUGEINTVAL
if(my $size=eval {
open(TEST, ">test.c") or die "Can't open test.c: $!";
print TEST <<'END';
#include <stdio.h>
int main() {
long long foo;
printf("%u", sizeof(foo));
return 0;
}
END
close TEST;

cc_build();
cc_run();
}) {
Configure::Data->set(
'hugeintval' => 'long long',
'hugeintvalsize' => $size
);
}
else {
Configure::Data->set(
'hugeintval' => 'long',
'hugeintvalsize' => Configure::Data->get('longsize')
);
}

cc_clean();

#get HUGEFLOATVAL
if(my $size=eval {
open(TEST, ">test.c") or die "Can't open test.c: $!";
print TEST <<'END';
#include <stdio.h>
int main() {
long double foo;
printf("%u", sizeof(foo));
return 0;
}
END
close TEST;

cc_build();
cc_run();
}) {
Configure::Data->set(
'hugefloatval' => 'long double',
'hugefloatvalsize' => $size
);
}
else {
Configure::Data->set(
'hugefloatval' => 'double',
'hugefloatvalsize' => Configure::Data->get('doublesize')
);
}

cc_clean();
}

1;
4 changes: 4 additions & 0 deletions config/gen/config_h/config_h.in
Expand Up @@ -48,6 +48,10 @@ typedef Parrot_Int INTVAL;
typedef Parrot_UInt UINTVAL;
typedef Parrot_Float FLOATVAL;

typedef ${hugeintval} HUGEINTVAL;
typedef unsigned ${hugeintval} UHUGEINTVAL;
typedef ${hugefloatval} HUGEFLOATVAL;

#define INTVAL_SIZE ${intvalsize}
#define NUMVAL_SIZE ${nvsize}
#define OPCODE_T_SIZE ${opcode_t_size}
Expand Down
17 changes: 11 additions & 6 deletions config/gen/makefiles/root.in
Expand Up @@ -96,10 +96,11 @@ INTERP_O_FILES = exceptions$(O) global_setup$(O) interpreter$(O) parrot$(O) \
packfile$(O) stacks$(O) string$(O) sub$(O) encoding$(O) \
chartype$(O) runops_cores$(O) trace$(O) pmc$(O) key$(O) hash$(O) \
core_pmcs$(O) platform$(O) ${jit_o} \
${gc_o} rx$(O) rxstacks$(O) intlist$(O) \
embed$(O) warnings$(O) misc$(O) ${cg_o} \
${gc_o} rx$(O) rxstacks$(O) intlist$(O) \
embed$(O) warnings$(O) ${cg_o} \
packout$(O) byteorder$(O) debug$(O) smallobject$(O) \
headers$(O) dod$(O) method_util$(O)
headers$(O) dod$(O) method_util$(O) \
misc$(O) spf_render$(O) spf_vtable$(O)

O_FILES = $(INTERP_O_FILES) \
$(IO_O_FILES) \
Expand All @@ -122,7 +123,7 @@ OPS_FILES = ${ops} $(GEN_OPSFILES)
CFLAGS = ${ccflags} ${cc_warn} ${cc_inc} ${cc_hasjit} ${cg_flag} ${gc_flag}

LINKFLAGS = ${linkflags}
LDFLAGS = ${ldflags}
LDFLAGS = ${ldflags} ${ld_debug}

C_LIBS = ${libs}

Expand Down Expand Up @@ -418,9 +419,13 @@ ${cg_c}

${gc_c}

warnings$(O) : $(H_FILES)
warnings$(O) : $(GENERAL_H_FILES)

misc$(O) : $(H_FILES)
misc$(O) : $(GENERAL_H_FILES)

spf_render$(O) : $(GENERAL_H_FILES)

spf_vtable$(O) : $(GENERAL_H_FILES)

# $(STICKY_FILES) : Configure.pl
# $(PERL) Configure.pl
Expand Down
14 changes: 7 additions & 7 deletions config/gen/platform/ansi.c
Expand Up @@ -27,7 +27,7 @@ Parrot_floatval_time(void)
{
/* unable to provide this level of precision under ANSI-C, so just fall
back to intval time for this. */
fprintf(stderr, "[ANSI] Parrot_floatval_time not accurate!\n");
Parrot_warn_c(NULL, PARROT_WARNINGS_PLATFORM_FLAG, "Parrot_floatval_time not accurate");
return (FLOATVAL)Parrot_intval_time();
}

Expand All @@ -39,7 +39,7 @@ Parrot_floatval_time(void)
void
Parrot_sleep(unsigned int seconds)
{
fprintf(stderr, "[ANSI] Parrot_sleep not implemented!\n");
Parrot_warn_c(NULL, PARROT_WARNINGS_PLATFORM_FLAG, "Parrot_sleep not implemented");
return;
}

Expand All @@ -50,7 +50,7 @@ Parrot_sleep(unsigned int seconds)
void
Parrot_setenv(const char *name, const char *value)
{
fprintf(stderr, "[ANSI] Parrot_setenv not implemented!\n");
Parrot_warn_c(NULL, PARROT_WARNINGS_PLATFORM_FLAG, "Parrot_setenv not implemented");
return;
}

Expand All @@ -62,7 +62,7 @@ Parrot_setenv(const char *name, const char *value)
void *
Parrot_dlopen(const char *filename)
{
fprintf(stderr, "[ANSI] Parrot_dlopen not implemented!\n");
Parrot_warn_c(NULL, PARROT_WARNINGS_PLATFORM_FLAG, "Parrot_dlopen not implemented");
return NULL;
}

Expand All @@ -74,7 +74,7 @@ Parrot_dlopen(const char *filename)
const char *
Parrot_dlerror(void)
{
return "[ANSI] Parrot_dlerror not implemented!\n";
return "Parrot_dlerror not implemented";
}


Expand All @@ -85,7 +85,7 @@ Parrot_dlerror(void)
void *
Parrot_dlsym(void *handle, const char *symbol)
{
fprintf(stderr, "[ANSI] Parrot_dlsym not implemented!\n");
Parrot_warn_c(NULL, PARROT_WARNINGS_PLATFORM_FLAG, "Parrot_dlsym not implemented");
return NULL;
}

Expand All @@ -97,7 +97,7 @@ Parrot_dlsym(void *handle, const char *symbol)
int
Parrot_dlclose(void *handle)
{
fprintf(stderr, "[ANSI] Parrot_dlclose not implemented!\n");
Parrot_warn_c(NULL, PARROT_WARNINGS_PLATFORM_FLAG, "Parrot_dlclose not implemented");
return 0;
}

Expand Down
4 changes: 3 additions & 1 deletion config/init/hints/mswin32.pl
Expand Up @@ -18,6 +18,7 @@
# The logo gets printed to STDERR; hence the redirection.
my $cc_output = `$cc 2>&1`;
$ccflags =~ s/-O1 // if $cc_output =~ m/Standard/;


Configure::Data->set(
so => '.dll',
Expand All @@ -26,7 +27,8 @@
cc_o_out => '-Fo',
cc_exe_out => '-Fe',
cc_ldflags => '/link',
cc_debug => '-Zi',
#Use Edit and Continue debugging if available
cc_debug => ($cc_output =~ /-ZI/? '-ZI' : '-Zi'),
ld_debug => '-debug',
ld_shared => '-dll',
ld_shared_flags=> '-def:libparrot.def',
Expand Down
30 changes: 30 additions & 0 deletions core.ops
Expand Up @@ -2155,8 +2155,38 @@ inline op pack(inout STR, in INT, in INT, in INT) {
goto NEXT();
}

=item C<sprintf>(out STR, in STR, in PMC)

=item C<sprintf>(out PMC, in PMC, in PMC)

=item C<sprintf>(out STR, in STR) [unimplemented]

=item C<sprintf>(out PMC, in PMC) [unimplemented]

Sets $1 to the result of calling C<Parrot_psprintf> with the
given format ($2) and arguments ($3, which should be an ordered
aggregate PMC). In the (unimplemented) versions that don't include
$3, arguments are popped off the user stack.

The result is quite similar to using the system C<sprintf>, but is
protected against buffer overflows and the like. There are some
differences, especially concerning sizes (which are largely ignored);
see F<misc.c> for details.

=back

inline op sprintf(out STR, in STR, in PMC) {
$1=Parrot_psprintf(interpreter, $2, $3);
goto NEXT();
}

inline op sprintf(out PMC, in PMC, in PMC) {
$1->vtable->set_string_native(interpreter, $1,
Parrot_psprintf(interpreter, $2->vtable->get_string(interpreter, $2), $3)
);
goto NEXT();
}

=cut

###############################################################################
Expand Down

0 comments on commit 53b5369

Please sign in to comment.