810 likes | 931 Views
Running Away to C. XS – More faff than fear London Perl Workshop – Dec 04 Alex Gough alex@earth.li. You’re here because…. You know some Perl You recognise some C But fear it a little You’re an evil brigand You know it’s warmer in here. Stack. Stack. Stack. Stack. Stack. Stack. Stack.
E N D
Running Away to C XS – More faff than fear London Perl Workshop – Dec 04Alex Goughalex@earth.li
You’re here because… • You know some Perl • You recognise some C • But fear it a little • You’re an evil brigand • You know it’s warmer in here
Stack Functions dSP; Declare stack varsPUSHMARK(SP) start of argumentsEXTEND make spaceXPUSHstuff push stuff, making spacePUSHstuff push stuff, need spacePUTBACK done adding arguments . . . Make a call . . .SPAGAIN refresh our stackret = POPstuff grab stuff from stackPUTBACK we’re done grabbing stuff
Scope • Start and end a scope • Tell Perl we’re creating temporary stuff • Tell Perl when we’re done with it
Scope Functions ENTER Opening brace {SAVETMPS start making temps . . . Call function . . .FREETMPS done with my temps LEAVE Closing brace }
Scalars $thing = 12 12.3 “harry” \ @array \ %hash \ $thing bless(\$object) *FILE qr{.*} {code}
Scalar Functions I SV* get_sv(char* name, I32 create)SV* sv = get_sv(“bar”, TRUE) SV* newSVx sv = newSViv(12) newSVnv(12.3) newSVpv(“honk”, 0) -> “honk” newSVpv(“honk”, 2) -> “ho”IV intv = SvIV(sv)NV fltv = SvNV(sv)char* foo = SvPV(sv)sv_setpv(sv, “honk”); sv_setiv(sv, 12)
Scalar Functions I SV* get_sv(char* name, I32 create)SV* sv = get_sv(“bar”, TRUE) SV* newSVx sv = newSViv(12) newSVnv(12.3) newSVpv(“honk”, 0) -> “honk” newSVpv(“honk”, 2) -> “ho”IV intv = SvIV(sv)NV fltv = SvNV(sv)char* foo = SvPV(sv)sv_setpv(sv, “honk”); sv_setiv(sv, 12)
Scalar Functions I SV* get_sv(char* name, I32 create)SV* sv = get_sv(“bar”, TRUE) SV* newSVx sv = newSViv(12) newSVnv(12.3) newSVpv(“honk”, 0) -> “honk” newSVpv(“honk”, 2) -> “ho”IV intv = SvIV(sv)NV fltv = SvNV(sv)char* foo = SvPV(sv)sv_setpv(sv, “honk”); sv_setiv(sv, 12)
Scalar Functions I SV* get_sv(char* name, I32 create)SV* sv = get_sv(“bar”, TRUE) SV* newSVx sv = newSViv(12) newSVnv(12.3) newSVpv(“honk”, 0) -> “honk” newSVpv(“honk”, 2) -> “ho”IV intv = SvIV(sv)NV fltv = SvNV(sv)char* foo = SvPV(sv)sv_setpv(sv, “honk”); sv_setiv(sv, 12)
Scalar Functions II SV* refsv = newRV_inc(sv) “refsv = \ sv” SV* sv = SvRV(refsv) “sv = $ { refsv }”I32 cnt = REFCNT(sv) REFCNT_inc(sv) REFCNT_dec(sv)SV *sv = sv_2mortal(newSViv(12)) sv_free(sv) sv_{catpv catsv cmp dec eq inc isa len . . . }
Scalar Functions II SV* refsv = newRV_inc(sv) “refsv = \ sv” SV* sv = SvRV(refsv) “sv = $ { refsv }”I32 cnt = REFCNT(sv) REFCNT_inc(sv) REFCNT_dec(sv)SV *sv = sv_2mortal(newSViv(12)) sv_free(sv) sv_{catpv catsv cmp dec eq inc isa len . . . }
Scalar Functions II SV* refsv = newRV_inc(sv) “refsv = \ sv” SV* sv = SvRV(refsv) “sv = $ { refsv }”I32 cnt = REFCNT(sv) REFCNT_inc(sv) REFCNT_dec(sv)SV *sv = sv_2mortal(newSViv(12)) sv_free(sv) sv_{catpv catsv cmp dec eq inc isa len . . . }
Scalar Functions II SV* refsv = newRV_inc(sv) “refsv = \ sv” SV* sv = SvRV(refsv) “sv = $ { refsv }”I32 cnt = REFCNT(sv) REFCNT_inc(sv) REFCNT_dec(sv)SV *sv = sv_2mortal(newSViv(12)) sv_free(sv) sv_{catpv catsv cmp dec eq inc isa len . . . }
A Puzzle • Find the longest set of three words that when listed form three letter words down all columns. padsareatend
Array Functions AV *av = get_av(“ARGV”, TRUE)SV** ret = av_store(av, 12, sv) SV** ret = av_fetch(av, 12, sv, lval) SV* sv = av_pop(av) av_shift(av) void av_push(av, sv) av_unshift(av, 3) [3 undefs] I32 len = av_len(av)
Hash Functions HV *hv = get_hv(“hash”, TRUE) BOOL hv_exists(hv, “key”, 3) SV** sv = hv_fetch(hv, “key”, 3, lval) SV** sv = hv_store(hv, “key”, 3, sv, 0) Or you can play with HE (Hash Entries)
Function Functions CV* cv = get_cv(“subname”, TRUE) call_pv(“subname”, context) call_sv(sv, context) Context: G_VOID } G_SCALAR } context G_ARRAY } G_NOARGS no arguments G_DISCARD “no return values” G_EVAL catch die in eval { } G_KEEPERR .. and be nice to $@
Objects, globs, whatever • Maybe you’ll need them • Maybe you won’t • See perlapi, perlcall, perlguts
Embedding • You have some C • You want to add a bit of Perl • Config file dabbling • Scripting engine • Hook into Efficient / Legacy code • Prototype features
Config Parsing • Flexible configuration framework • C side factored into:void get_config(char* key, char* dst, int len); • Let Perl provide the intelligence • (We provide the glue)
Perl • A big C program • A really tiny main() • Constructs an intepreter • Tells it to parse your script • Tells it to run your script • Jumps between C and Perl a lot • Cleans up (sort of) • Exits
Config Parsing use strict; my %config = (); sub init { my($file) = @_; … # fill in %config } sub get_value { my($key) = @_; return $config{$key} || “”; }
#include "EXTERN.h" #include "Perl.h" static PerlInterpreter *g_perl_interp; int main(int argc, char** argv, char** env) { char *config_pl[] = {“config.pl”, 0}; PERL_SYS_INIT3(&argc,&argv,&env); g_perl_interp = perl_alloc(); perl_construct(g_perl_interp); PL_exit_flags |= PERL_EXIT_DESTRUCT_END; perl_parse(g_perl_interp, NULL, 1, config_pl, env); perl_run(g_perl_interp); do_program_stuff(. . .); perl_destruct(g_perl_interp); perl_free(g_perl_interp); PERL_SYS_TERM() }
#include "EXTERN.h" #include "Perl.h" static PerlInterpreter *g_perl_interp; int main(int argc, char** argv, char** env) { char *config_pl[] = {“config.pl”, 0}; PERL_SYS_INIT3(&argc,&argv,&env); g_perl_interp = perl_alloc(); perl_construct(g_perl_interp); PL_exit_flags |= PERL_EXIT_DESTRUCT_END; perl_parse(g_perl_interp, NULL, 1, config_pl, env); perl_run(g_perl_interp); do_program_stuff(. . .); perl_destruct(g_perl_interp); perl_free(g_perl_interp); PERL_SYS_TERM() }
#include "EXTERN.h" #include "Perl.h" static PerlInterpreter *g_perl_interp; int main(int argc, char** argv, char** env) { char *config_pl[] = {“config.pl”, 0}; PERL_SYS_INIT3(&argc,&argv,&env); g_perl_interp = perl_alloc(); perl_construct(g_perl_interp); PL_exit_flags |= PERL_EXIT_DESTRUCT_END; perl_parse(g_perl_interp, NULL, 1, config_pl, env); perl_run(g_perl_interp); do_program_stuff(. . .); perl_destruct(g_perl_interp); perl_free(g_perl_interp); PERL_SYS_TERM() }
#include "EXTERN.h" #include "Perl.h" static PerlInterpreter *g_perl_interp; int main(int argc, char** argv, char** env) { char *config_pl[] = {“config.pl”, 0}; PERL_SYS_INIT3(&argc,&argv,&env); g_perl_interp = perl_alloc(); perl_construct(g_perl_interp); PL_exit_flags |= PERL_EXIT_DESTRUCT_END; perl_parse(g_perl_interp, NULL, 1, config_pl, env); perl_run(g_perl_interp); do_program_stuff(. . .); perl_destruct(g_perl_interp); perl_free(g_perl_interp); PERL_SYS_TERM() }
#include "EXTERN.h" #include "Perl.h" static PerlInterpreter *g_perl_interp; int main(int argc, char** argv, char** env) { char *config_pl[] = {“config.pl”, 0}; PERL_SYS_INIT3(&argc,&argv,&env); g_perl_interp = perl_alloc(); perl_construct(g_perl_interp); PL_exit_flags |= PERL_EXIT_DESTRUCT_END; perl_parse(g_perl_interp, NULL, 1, config_pl, env); perl_run(g_perl_interp); do_program_stuff(. . .); perl_destruct(g_perl_interp); perl_free(g_perl_interp); PERL_SYS_TERM() }
#include "EXTERN.h" #include "Perl.h" static PerlInterpreter *g_perl_interp; int main(int argc, char** argv, char** env) { char *config_pl[] = {“config.pl”, 0}; PERL_SYS_INIT3(&argc,&argv,&env); g_perl_interp = perl_alloc(); perl_construct(g_perl_interp); PL_exit_flags |= PERL_EXIT_DESTRUCT_END; perl_parse(g_perl_interp, NULL, 1, config_pl, env); perl_run(g_perl_interp); do_program_stuff(. . .); perl_destruct(g_perl_interp); perl_free(g_perl_interp); PERL_SYS_TERM() }
void get_config(char* key, char* dst) {dSP; SV *ret = NULL; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(sv_2mortal(newSVpv(key))); PUTBACK; call_pv("get_value", G_SCALAR); SPAGAIN; ret = POPs; strcpy(dst, SvPV); PUTBACK; FREETMPS; LEAVE;}
void get_config(char* key, char* dst) {dSP; SV *ret = NULL;ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(sv_2mortal(newSVpv(key))); PUTBACK; call_pv("get_value", G_SCALAR); SPAGAIN; ret = POPs; strcpy(dst, SvPV); PUTBACK; FREETMPS; LEAVE;}
void get_config(char* key, char* dst) {dSP; SV *ret = NULL; ENTER; SAVETMPS; PUSHMARK(SP);XPUSHs(sv_2mortal(newSVpv(key))); PUTBACK; call_pv("get_value", G_SCALAR); SPAGAIN; ret = POPs; strcpy(dst, SvPV); PUTBACK; FREETMPS; LEAVE;}
void get_config(char* key, char* dst) {dSP; SV *ret = NULL; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(sv_2mortal(newSVpv(key)));PUTBACK;call_pv("get_value", G_SCALAR); SPAGAIN; ret = POPs; strcpy(dst, SvPV); PUTBACK; FREETMPS; LEAVE;}
void get_config(char* key, char* dst) {dSP; SV *ret = NULL; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(sv_2mortal(newSVpv(key))); PUTBACK; call_pv("get_value", G_SCALAR); SPAGAIN; ret = POPs; strcpy(dst, SvPV); PUTBACK; FREETMPS; LEAVE;}
void get_config(char* key, char* dst) {dSP; SV *ret = NULL; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(sv_2mortal(newSVpv(key))); PUTBACK; call_pv("get_value", G_SCALAR); SPAGAIN;ret = POPs; strcpy(dst, SvPV); PUTBACK; FREETMPS; LEAVE;}