For Programmers: Free Programming Magazines  


Home > Archive > PERL Miscellaneous > July 2005 > How to return list from Inline::C code?









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author How to return list from Inline::C code?
kj

2005-07-29, 5:04 pm




I'm attempting to hack the Perl internals, something I know very
little of. So I apologize ahead of time for the cluelessness of
this question.

I want to implement a function via Inline::C such that, depending
on context, it returns either a scalar or a list of two values.
(This function will access the internals of other variables, and I
want to make it as fast as possible, hence the decision to code it
in C).

Since C is not capable of optionally returning a scalar or a list,
I don't even know where to begin with this.

Any advice would be much appreciated. In particular, I'd love to
look at source code for a simple function (in C) that returns a
scalar or a list according to calling context.

Thanks!

kj

--
NOTE: In my address everything before the first period is backwards;
and the last period, and everything after it, should be discarded.
William Ahern

2005-07-29, 5:04 pm

kj <socyl@987jk.com.invalid> wrote:
> I'm attempting to hack the Perl internals, something I know very
> little of. So I apologize ahead of time for the cluelessness of
> this question.


Hack the Perl internals, or just use the Perl internals directly from C?

From here on out this is coming from Perl XS experience, not Inline::C. I've
never used Inline::C so I don't know that the differences are.

> I want to implement a function via Inline::C such that, depending
> on context, it returns either a scalar or a list of two values.
> (This function will access the internals of other variables, and I
> want to make it as fast as possible, hence the decision to code it
> in C).
>
> Since C is not capable of optionally returning a scalar or a list,
> I don't even know where to begin with this.


If you read the perlapi man page/pod you'll come across the GIMME_V
C macro. GIMME_V can return G_SCALAR, G_ARRAY or G_VOID.

You can then decide based on those three conditions how many return values
to push onto the stack.

Realize, also, that you can't return an array directly. If you want to
return an array you have to push each array member onto the stack. For large
arrays it's far more efficient to return a single scalar which is a
reference to an array.

> Any advice would be much appreciated. In particular, I'd love to
> look at source code for a simple function (in C) that returns a
> scalar or a list according to calling context.


Read perlxstut, perlxs, perlapi and perlguts. Anything else will just
confuse you, and they have great examples in there already.

Apologies if any of this is entirely inapplicable to Inline::C.

tlviewer

2005-07-29, 5:04 pm


"kj" <socyl@987jk.com.invalid> wrote in message =
news:dce677$blb$1@reader2.panix.com...
>=20
>=20
>=20
> I'm attempting to hack the Perl internals, something I know very
> little of. So I apologize ahead of time for the cluelessness of
> this question.
>=20
> I want to implement a function via Inline::C such that, depending
> on context, it returns either a scalar or a list of two values.
> (This function will access the internals of other variables, and I
> want to make it as fast as possible, hence the decision to code it
> in C).
>=20
> Since C is not capable of optionally returning a scalar or a list,
> I don't even know where to begin with this.
>=20
> Any advice would be much appreciated. In particular, I'd love to
> look at source code for a simple function (in C) that returns a
> scalar or a list according to calling context.
>=20
> Thanks!
>=20
> kj


In the inline script below, see how I return a perl list
ref from main().

hth,
tlviewer

# begin Chmdump.pl
use Inline C =3D> DATA =3D> LIBS =3D> '-luser32';

my $tStart =3D Win32::GetTickCount();
my $arref;
my ( $in, $out );=20

$|=3D 1;

$in =3D 'i:/temp/Javascript Manual Of Style.chm'; =20
#
$out =3D '/#STRINGS'; =20

my $dir =3D '.';

$arref =3D main($in, $out, $dir );

for my $name (@$arref){
print $name, "\n";
}=20

=20
# /* Win32 only way to get the elapsed time */
print "elapsed=3D", ( Win32::GetTickCount() - $tStart ) / 1000, " =
seconds\n";

#
__END__
__C__
/* test */
#define _WIN32_WINNT 0x0500=20
#include <windows.h>
#include <stdio.h>
#include <limits.h>
#include <errno.h>
#include "chmlib.h"=20

// pass arguments 2 ways to show flexible Ingy style! =20
AV* main( SV* infname, char* ext_file, char* outdirname)
{ =20
AV* array =3D newAV(); =20
ulong length;
chmfile *c;
ulong all_len;
int i;
=20
ubyte *outbuf;
ulong namelen;
//
char dirname[255];
int err;
int lres;
=20
// =20

fprintf( stdout, "fname=3D %s \n", SvPV(infname, PL_na) );
c =3D chm_openfile(SvPV(infname, PL_na)); //infname

if (!c) { =20
fprintf( stdout, "failed to open %s \n", infname );
perror("chm_openfile");
exit(-1);
} =20
=20
//Inline_Stack_Reset;=20
=20
for (i =3D 0; i < c->dir->nentries; i++) { =20
av_push(array, newSVpvf("%s", c->dir->entry[i].name));
//fprintf(stdout,"%d =3D %s \n", i, c->dir->entry[i].name);=20
}=20
//
=20
fprintf(stdout,"name=3D %s \n", c->dir->entry[3].name);
//=20
=20
fprintf( stdout, "calling getfile \n" );
lres =3D chm_getfile(c, ext_file , &length, &outbuf);
if (lres !=3D 0) {=20
fprintf( stdout, "died in getfile \n" );
exit(-1);
}
//
=20
fprintf( stdout, "Length=3D%d \n", length);
namelen=3D strlen((char*) (outbuf+1));

// if buffer has embedded nulls, then parse out the tokens (#STRINGS)
if ( namelen < 15) {
=20
strncpy(dirname,outbuf+1, namelen+1);
fprintf( stdout, "char=3D%s \n", (char*)(outbuf+1));
=20
all_len =3D 0;
while (all_len +2 < length){
//
if (namelen>0) fprintf( stdout, "%s\n", (char*)(outbuf+1+all_len)); =

all_len +=3Dnamelen+1;
//
namelen =3D strlen( (char*)(outbuf+all_len+1));=20
}
}
else{
fprintf( stdout, "file_len=3D%i oblen=3D%i\n", length, strlen(outbuf));
fwrite( outbuf,1, length, stdout );
}

//=20
=20
=20
=20

chm_close(c);=20
if (outbuf) free(outbuf);=20
return array;
} // end main=20

static void usage(char *pname)
{
fprintf(stderr, "Usage: %s chmfile outdir\n", pname);
}

// supporting libraries
#include "chmlib.c"=20
#include "lzx.c"

Sisyphus

2005-07-29, 10:01 pm


"kj" <socyl@987jk.com.invalid> wrote in message
news:dce677$blb$1@reader2.panix.com...
>
>
>
> I'm attempting to hack the Perl internals, something I know very
> little of. So I apologize ahead of time for the cluelessness of
> this question.
>
> I want to implement a function via Inline::C such that, depending
> on context, it returns either a scalar or a list of two values.
> (This function will access the internals of other variables, and I
> want to make it as fast as possible, hence the decision to code it
> in C).
>
> Since C is not capable of optionally returning a scalar or a list,
> I don't even know where to begin with this.
>
> Any advice would be much appreciated. In particular, I'd love to
> look at source code for a simple function (in C) that returns a
> scalar or a list according to calling context.
>


As William Ahern pointed out, GIMME_V seems to be your friend here:

D:\pscrpt\inline\special>type gimme_v.pl

use warnings;
use Inline C => Config =>
BUILD_NOISY => 1;

use Inline C => <<'EOC';

void foo() {
Inline_Stack_Vars;

if(GIMME_V == G_SCALAR) {
printf("%s\n", "return scalar");
Inline_Stack_Reset;
Inline_Stack_Push(sv_2mortal(newSViv(42)
));
Inline_Stack_Done;
Inline_Stack_Return(1);
}

if(GIMME_V == G_ARRAY) {
printf("%s\n", "return array");
Inline_Stack_Reset;
Inline_Stack_Push(sv_2mortal(newSViv(655
37)));
Inline_Stack_Push(sv_2mortal(newSViv(655
39)));
Inline_Stack_Done;
Inline_Stack_Return(2);
}

if(GIMME_V == G_VOID) {
printf("Nothing to do ... \n");
Inline_Stack_Void;
}

}



EOC

$x = foo();
print $x, "\n\n";

@y = foo();
print "@y\n\n";

foo();

__END__
D:\pscrpt\inline\special>perl gimme_v.pl
return scalar
42

return array
65537 65539

Nothing to do ...

Cheers,
Rob


kj

2005-07-29, 10:01 pm


Many thanks for all the replies! I'm in business now.

kj

--
NOTE: In my address everything before the first period is backwards;
and the last period, and everything after it, should be discarded.
Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2009 codecomments.com