From fc22b3d6507c6745911b9dfcc68f1e665ae13dbc Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 15 Apr 2024 21:43:11 +0200 Subject: Adding upstream version 4.22.0. Signed-off-by: Daniel Baumann --- upstream/mageia-cauldron/man1/perlembed.1 | 1246 +++++++++++++++++++++++++++++ 1 file changed, 1246 insertions(+) create mode 100644 upstream/mageia-cauldron/man1/perlembed.1 (limited to 'upstream/mageia-cauldron/man1/perlembed.1') diff --git a/upstream/mageia-cauldron/man1/perlembed.1 b/upstream/mageia-cauldron/man1/perlembed.1 new file mode 100644 index 00000000..b8de30ac --- /dev/null +++ b/upstream/mageia-cauldron/man1/perlembed.1 @@ -0,0 +1,1246 @@ +.\" -*- mode: troff; coding: utf-8 -*- +.\" Automatically generated by Pod::Man 5.01 (Pod::Simple 3.43) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" \*(C` and \*(C' are quotes in nroff, nothing in troff, for use with C<>. +.ie n \{\ +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds C` +. ds C' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is >0, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.\" +.\" Avoid warning from groff about undefined register 'F'. +.de IX +.. +.nr rF 0 +.if \n(.g .if rF .nr rF 1 +.if (\n(rF:(\n(.g==0)) \{\ +. if \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. if !\nF==2 \{\ +. nr % 0 +. nr F 2 +. \} +. \} +.\} +.rr rF +.\" ======================================================================== +.\" +.IX Title "PERLEMBED 1" +.TH PERLEMBED 1 2023-11-28 "perl v5.38.2" "Perl Programmers Reference Guide" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH NAME +perlembed \- how to embed perl in your C program +.SH DESCRIPTION +.IX Header "DESCRIPTION" +.SS PREAMBLE +.IX Subsection "PREAMBLE" +Do you want to: +.IP "\fBUse C from Perl?\fR" 5 +.IX Item "Use C from Perl?" +Read perlxstut, perlxs, h2xs, perlguts, and perlapi. +.IP "\fBUse a Unix program from Perl?\fR" 5 +.IX Item "Use a Unix program from Perl?" +Read about back-quotes and about \f(CW\*(C`system\*(C'\fR and \f(CW\*(C`exec\*(C'\fR in perlfunc. +.IP "\fBUse Perl from Perl?\fR" 5 +.IX Item "Use Perl from Perl?" +Read about "do" in perlfunc and "eval" in perlfunc and "require" in perlfunc +and "use" in perlfunc. +.IP "\fBUse C from C?\fR" 5 +.IX Item "Use C from C?" +Rethink your design. +.IP "\fBUse Perl from C?\fR" 5 +.IX Item "Use Perl from C?" +Read on... +.SS ROADMAP +.IX Subsection "ROADMAP" +.IP \(bu 5 +Compiling your C program +.IP \(bu 5 +Adding a Perl interpreter to your C program +.IP \(bu 5 +Calling a Perl subroutine from your C program +.IP \(bu 5 +Evaluating a Perl statement from your C program +.IP \(bu 5 +Performing Perl pattern matches and substitutions from your C program +.IP \(bu 5 +Fiddling with the Perl stack from your C program +.IP \(bu 5 +Maintaining a persistent interpreter +.IP \(bu 5 +Maintaining multiple interpreter instances +.IP \(bu 5 +Using Perl modules, which themselves use C libraries, from your C program +.IP \(bu 5 +Embedding Perl under Win32 +.SS "Compiling your C program" +.IX Subsection "Compiling your C program" +If you have trouble compiling the scripts in this documentation, +you're not alone. The cardinal rule: COMPILE THE PROGRAMS IN EXACTLY +THE SAME WAY THAT YOUR PERL WAS COMPILED. (Sorry for yelling.) +.PP +Also, every C program that uses Perl must link in the \fIperl library\fR. +What's that, you ask? Perl is itself written in C; the perl library +is the collection of compiled C programs that were used to create your +perl executable (\fI/usr/bin/perl\fR or equivalent). (Corollary: you +can't use Perl from your C program unless Perl has been compiled on +your machine, or installed properly\-\-that's why you shouldn't blithely +copy Perl executables from machine to machine without also copying the +\&\fIlib\fR directory.) +.PP +When you use Perl from C, your C program will\-\-usually\-\-allocate, +"run", and deallocate a \fIPerlInterpreter\fR object, which is defined by +the perl library. +.PP +If your copy of Perl is recent enough to contain this documentation +(version 5.002 or later), then the perl library (and \fIEXTERN.h\fR and +\&\fIperl.h\fR, which you'll also need) will reside in a directory +that looks like this: +.PP +.Vb 1 +\& /usr/local/lib/perl5/your_architecture_here/CORE +.Ve +.PP +or perhaps just +.PP +.Vb 1 +\& /usr/local/lib/perl5/CORE +.Ve +.PP +or maybe something like +.PP +.Vb 1 +\& /usr/opt/perl5/CORE +.Ve +.PP +Execute this statement for a hint about where to find CORE: +.PP +.Vb 1 +\& perl \-MConfig \-e \*(Aqprint $Config{archlib}\*(Aq +.Ve +.PP +Here's how you'd compile the example in the next section, +"Adding a Perl interpreter to your C program", on my Linux box: +.PP +.Vb 4 +\& % gcc \-O2 \-Dbool=char \-DHAS_BOOL \-I/usr/local/include +\& \-I/usr/local/lib/perl5/i586\-linux/5.003/CORE +\& \-L/usr/local/lib/perl5/i586\-linux/5.003/CORE +\& \-o interp interp.c \-lperl \-lm +.Ve +.PP +(That's all one line.) On my DEC Alpha running old 5.003_05, the +incantation is a bit different: +.PP +.Vb 4 +\& % cc \-O2 \-Olimit 2900 \-I/usr/local/include +\& \-I/usr/local/lib/perl5/alpha\-dec_osf/5.00305/CORE +\& \-L/usr/local/lib/perl5/alpha\-dec_osf/5.00305/CORE \-L/usr/local/lib +\& \-D_\|_LANGUAGE_C_\|_ \-D_NO_PROTO \-o interp interp.c \-lperl \-lm +.Ve +.PP +How can you figure out what to add? Assuming your Perl is post\-5.001, +execute a \f(CW\*(C`perl \-V\*(C'\fR command and pay special attention to the "cc" and +"ccflags" information. +.PP +You'll have to choose the appropriate compiler (\fIcc\fR, \fIgcc\fR, et al.) for +your machine: \f(CW\*(C`perl \-MConfig \-e \*(Aqprint $Config{cc}\*(Aq\*(C'\fR will tell you what +to use. +.PP +You'll also have to choose the appropriate library directory +(\fI/usr/local/lib/...\fR) for your machine. If your compiler complains +that certain functions are undefined, or that it can't locate +\&\fI\-lperl\fR, then you need to change the path following the \f(CW\*(C`\-L\*(C'\fR. If it +complains that it can't find \fIEXTERN.h\fR and \fIperl.h\fR, you need to +change the path following the \f(CW\*(C`\-I\*(C'\fR. +.PP +You may have to add extra libraries as well. Which ones? +Perhaps those printed by +.PP +.Vb 1 +\& perl \-MConfig \-e \*(Aqprint $Config{libs}\*(Aq +.Ve +.PP +Provided your perl binary was properly configured and installed the +\&\fBExtUtils::Embed\fR module will determine all of this information for +you: +.PP +.Vb 1 +\& % cc \-o interp interp.c \`perl \-MExtUtils::Embed \-e ccopts \-e ldopts\` +.Ve +.PP +If the \fBExtUtils::Embed\fR module isn't part of your Perl distribution, +you can retrieve it from + +(If this documentation came from your Perl distribution, then you're +running 5.004 or better and you already have it.) +.PP +The \fBExtUtils::Embed\fR kit on CPAN also contains all source code for +the examples in this document, tests, additional examples and other +information you may find useful. +.SS "Adding a Perl interpreter to your C program" +.IX Subsection "Adding a Perl interpreter to your C program" +In a sense, perl (the C program) is a good example of embedding Perl +(the language), so I'll demonstrate embedding with \fIminiperlmain.c\fR, +included in the source distribution. Here's a bastardized, non-portable +version of \fIminiperlmain.c\fR containing the essentials of embedding: +.PP +.Vb 2 +\& #include /* from the Perl distribution */ +\& #include /* from the Perl distribution */ +\& +\& static PerlInterpreter *my_perl; /*** The Perl interpreter ***/ +\& +\& int main(int argc, char **argv, char **env) +\& { +\& PERL_SYS_INIT3(&argc,&argv,&env); +\& my_perl = perl_alloc(); +\& perl_construct(my_perl); +\& PL_exit_flags |= PERL_EXIT_DESTRUCT_END; +\& perl_parse(my_perl, NULL, argc, argv, (char **)NULL); +\& perl_run(my_perl); +\& perl_destruct(my_perl); +\& perl_free(my_perl); +\& PERL_SYS_TERM(); +\& exit(EXIT_SUCCESS); +\& } +.Ve +.PP +Notice that we don't use the \f(CW\*(C`env\*(C'\fR pointer. Normally handed to +\&\f(CW\*(C`perl_parse\*(C'\fR as its final argument, \f(CW\*(C`env\*(C'\fR here is replaced by +\&\f(CW\*(C`NULL\*(C'\fR, which means that the current environment will be used. +.PP +The macros \fBPERL_SYS_INIT3()\fR and \fBPERL_SYS_TERM()\fR provide system-specific +tune up of the C runtime environment necessary to run Perl interpreters; +they should only be called once regardless of how many interpreters you +create or destroy. Call \fBPERL_SYS_INIT3()\fR before you create your first +interpreter, and \fBPERL_SYS_TERM()\fR after you free your last interpreter. +.PP +Since \fBPERL_SYS_INIT3()\fR may change \f(CW\*(C`env\*(C'\fR, it may be more appropriate to +provide \f(CW\*(C`env\*(C'\fR as an argument to \fBperl_parse()\fR. +.PP +Also notice that no matter what arguments you pass to \fBperl_parse()\fR, +\&\fBPERL_SYS_INIT3()\fR must be invoked on the C \fBmain()\fR argc, argv and env and +only once. +.PP +Mind that argv[argc] must be NULL, same as those passed to a main +function in C. +.PP +Now compile this program (I'll call it \fIinterp.c\fR) into an executable: +.PP +.Vb 1 +\& % cc \-o interp interp.c \`perl \-MExtUtils::Embed \-e ccopts \-e ldopts\` +.Ve +.PP +After a successful compilation, you'll be able to use \fIinterp\fR just +like perl itself: +.PP +.Vb 6 +\& % interp +\& print "Pretty Good Perl \en"; +\& print "10890 \- 9801 is ", 10890 \- 9801; +\& +\& Pretty Good Perl +\& 10890 \- 9801 is 1089 +.Ve +.PP +or +.PP +.Vb 2 +\& % interp \-e \*(Aqprintf("%x", 3735928559)\*(Aq +\& deadbeef +.Ve +.PP +You can also read and execute Perl statements from a file while in the +midst of your C program, by placing the filename in \fIargv[1]\fR before +calling \fIperl_run\fR. +.SS "Calling a Perl subroutine from your C program" +.IX Subsection "Calling a Perl subroutine from your C program" +To call individual Perl subroutines, you can use any of the \fBcall_*\fR +functions documented in perlcall. +In this example we'll use \f(CW\*(C`call_argv\*(C'\fR. +.PP +That's shown below, in a program I'll call \fIshowtime.c\fR. +.PP +.Vb 2 +\& #include +\& #include +\& +\& static PerlInterpreter *my_perl; +\& +\& int main(int argc, char **argv, char **env) +\& { +\& char *args[] = { NULL }; +\& PERL_SYS_INIT3(&argc,&argv,&env); +\& my_perl = perl_alloc(); +\& perl_construct(my_perl); +\& +\& perl_parse(my_perl, NULL, argc, argv, NULL); +\& PL_exit_flags |= PERL_EXIT_DESTRUCT_END; +\& +\& /*** skipping perl_run() ***/ +\& +\& call_argv("showtime", G_DISCARD | G_NOARGS, args); +\& +\& perl_destruct(my_perl); +\& perl_free(my_perl); +\& PERL_SYS_TERM(); +\& exit(EXIT_SUCCESS); +\& } +.Ve +.PP +where \fIshowtime\fR is a Perl subroutine that takes no arguments (that's the +\&\fIG_NOARGS\fR) and for which I'll ignore the return value (that's the +\&\fIG_DISCARD\fR). Those flags, and others, are discussed in perlcall. +.PP +I'll define the \fIshowtime\fR subroutine in a file called \fIshowtime.pl\fR: +.PP +.Vb 1 +\& print "I shan\*(Aqt be printed."; +\& +\& sub showtime { +\& print time; +\& } +.Ve +.PP +Simple enough. Now compile and run: +.PP +.Vb 4 +\& % cc \-o showtime showtime.c \e +\& \`perl \-MExtUtils::Embed \-e ccopts \-e ldopts\` +\& % showtime showtime.pl +\& 818284590 +.Ve +.PP +yielding the number of seconds that elapsed between January 1, 1970 +(the beginning of the Unix epoch), and the moment I began writing this +sentence. +.PP +In this particular case we don't have to call \fIperl_run\fR, as we set +the PL_exit_flag PERL_EXIT_DESTRUCT_END which executes END blocks in +perl_destruct. +.PP +If you want to pass arguments to the Perl subroutine, you can add +strings to the \f(CW\*(C`NULL\*(C'\fR\-terminated \f(CW\*(C`args\*(C'\fR list passed to +\&\fIcall_argv\fR. For other data types, or to examine return values, +you'll need to manipulate the Perl stack. That's demonstrated in +"Fiddling with the Perl stack from your C program". +.SS "Evaluating a Perl statement from your C program" +.IX Subsection "Evaluating a Perl statement from your C program" +Perl provides two API functions to evaluate pieces of Perl code. +These are "eval_sv" in perlapi and "eval_pv" in perlapi. +.PP +Arguably, these are the only routines you'll ever need to execute +snippets of Perl code from within your C program. Your code can be as +long as you wish; it can contain multiple statements; it can employ +"use" in perlfunc, "require" in perlfunc, and "do" in perlfunc to +include external Perl files. +.PP +\&\fIeval_pv\fR lets us evaluate individual Perl strings, and then +extract variables for coercion into C types. The following program, +\&\fIstring.c\fR, executes three Perl strings, extracting an \f(CW\*(C`int\*(C'\fR from +the first, a \f(CW\*(C`float\*(C'\fR from the second, and a \f(CW\*(C`char *\*(C'\fR from the third. +.PP +.Vb 2 +\& #include +\& #include +\& +\& static PerlInterpreter *my_perl; +\& +\& main (int argc, char **argv, char **env) +\& { +\& char *embedding[] = { "", "\-e", "0", NULL }; +\& +\& PERL_SYS_INIT3(&argc,&argv,&env); +\& my_perl = perl_alloc(); +\& perl_construct( my_perl ); +\& +\& perl_parse(my_perl, NULL, 3, embedding, NULL); +\& PL_exit_flags |= PERL_EXIT_DESTRUCT_END; +\& perl_run(my_perl); +\& +\& /** Treat $a as an integer **/ +\& eval_pv("$a = 3; $a **= 2", TRUE); +\& printf("a = %d\en", SvIV(get_sv("a", 0))); +\& +\& /** Treat $a as a float **/ +\& eval_pv("$a = 3.14; $a **= 2", TRUE); +\& printf("a = %f\en", SvNV(get_sv("a", 0))); +\& +\& /** Treat $a as a string **/ +\& eval_pv( +\& "$a = \*(AqrekcaH lreP rehtonA tsuJ\*(Aq; $a = reverse($a);", TRUE); +\& printf("a = %s\en", SvPV_nolen(get_sv("a", 0))); +\& +\& perl_destruct(my_perl); +\& perl_free(my_perl); +\& PERL_SYS_TERM(); +\& } +.Ve +.PP +All of those strange functions with \fIsv\fR in their names help convert Perl +scalars to C types. They're described in perlguts and perlapi. +.PP +If you compile and run \fIstring.c\fR, you'll see the results of using +\&\fR\f(BISvIV()\fR\fI\fR to create an \f(CW\*(C`int\*(C'\fR, \fI\fR\f(BISvNV()\fR\fI\fR to create a \f(CW\*(C`float\*(C'\fR, and +\&\fI\fR\f(BISvPV()\fR\fI\fR to create a string: +.PP +.Vb 3 +\& a = 9 +\& a = 9.859600 +\& a = Just Another Perl Hacker +.Ve +.PP +In the example above, we've created a global variable to temporarily +store the computed value of our eval'ed expression. It is also +possible and in most cases a better strategy to fetch the return value +from \fR\f(BIeval_pv()\fR\fI\fR instead. Example: +.PP +.Vb 4 +\& ... +\& SV *val = eval_pv("reverse \*(AqrekcaH lreP rehtonA tsuJ\*(Aq", TRUE); +\& printf("%s\en", SvPV_nolen(val)); +\& ... +.Ve +.PP +This way, we avoid namespace pollution by not creating global +variables and we've simplified our code as well. +.SS "Performing Perl pattern matches and substitutions from your C program" +.IX Subsection "Performing Perl pattern matches and substitutions from your C program" +The \fR\f(BIeval_sv()\fR\fI\fR function lets us evaluate strings of Perl code, so we can +define some functions that use it to "specialize" in matches and +substitutions: \fI\fR\f(BImatch()\fR\fI\fR, \fI\fR\f(BIsubstitute()\fR\fI\fR, and \fI\fR\f(BImatches()\fR\fI\fR. +.PP +.Vb 1 +\& I32 match(SV *string, char *pattern); +.Ve +.PP +Given a string and a pattern (e.g., \f(CW\*(C`m/clasp/\*(C'\fR or \f(CW\*(C`/\eb\ew*\eb/\*(C'\fR, which +in your C program might appear as "/\e\eb\e\ew*\e\eb/"), \fBmatch()\fR +returns 1 if the string matches the pattern and 0 otherwise. +.PP +.Vb 1 +\& int substitute(SV **string, char *pattern); +.Ve +.PP +Given a pointer to an \f(CW\*(C`SV\*(C'\fR and an \f(CW\*(C`=~\*(C'\fR operation (e.g., +\&\f(CW\*(C`s/bob/robert/g\*(C'\fR or \f(CW\*(C`tr[A\-Z][a\-z]\*(C'\fR), \fBsubstitute()\fR modifies the string +within the \f(CW\*(C`SV\*(C'\fR as according to the operation, returning the number of +substitutions made. +.PP +.Vb 1 +\& SSize_t matches(SV *string, char *pattern, AV **matches); +.Ve +.PP +Given an \f(CW\*(C`SV\*(C'\fR, a pattern, and a pointer to an empty \f(CW\*(C`AV\*(C'\fR, +\&\fBmatches()\fR evaluates \f(CW\*(C`$string =~ $pattern\*(C'\fR in a list context, and +fills in \fImatches\fR with the array elements, returning the number of matches +found. +.PP +Here's a sample program, \fImatch.c\fR, that uses all three (long lines have +been wrapped here): +.PP +.Vb 2 +\& #include +\& #include +\& +\& static PerlInterpreter *my_perl; +\& +\& /** my_eval_sv(code, error_check) +\& ** kinda like eval_sv(), +\& ** but we pop the return value off the stack +\& **/ +\& SV* my_eval_sv(SV *sv, I32 croak_on_error) +\& { +\& dSP; +\& SV* retval; +\& +\& +\& PUSHMARK(SP); +\& eval_sv(sv, G_SCALAR); +\& +\& SPAGAIN; +\& retval = POPs; +\& PUTBACK; +\& +\& if (croak_on_error && SvTRUE(ERRSV)) +\& croak_sv(ERRSV); +\& +\& return retval; +\& } +\& +\& /** match(string, pattern) +\& ** +\& ** Used for matches in a scalar context. +\& ** +\& ** Returns 1 if the match was successful; 0 otherwise. +\& **/ +\& +\& I32 match(SV *string, char *pattern) +\& { +\& SV *command = newSV(0), *retval; +\& +\& sv_setpvf(command, "my $string = \*(Aq%s\*(Aq; $string =~ %s", +\& SvPV_nolen(string), pattern); +\& +\& retval = my_eval_sv(command, TRUE); +\& SvREFCNT_dec(command); +\& +\& return SvIV(retval); +\& } +\& +\& /** substitute(string, pattern) +\& ** +\& ** Used for =~ operations that +\& ** modify their left\-hand side (s/// and tr///) +\& ** +\& ** Returns the number of successful matches, and +\& ** modifies the input string if there were any. +\& **/ +\& +\& I32 substitute(SV **string, char *pattern) +\& { +\& SV *command = newSV(0), *retval; +\& +\& sv_setpvf(command, "$string = \*(Aq%s\*(Aq; ($string =~ %s)", +\& SvPV_nolen(*string), pattern); +\& +\& retval = my_eval_sv(command, TRUE); +\& SvREFCNT_dec(command); +\& +\& *string = get_sv("string", 0); +\& return SvIV(retval); +\& } +\& +\& /** matches(string, pattern, matches) +\& ** +\& ** Used for matches in a list context. +\& ** +\& ** Returns the number of matches, +\& ** and fills in **matches with the matching substrings +\& **/ +\& +\& SSize_t matches(SV *string, char *pattern, AV **match_list) +\& { +\& SV *command = newSV(0); +\& SSize_t num_matches; +\& +\& sv_setpvf(command, "my $string = \*(Aq%s\*(Aq; @array = ($string =~ %s)", +\& SvPV_nolen(string), pattern); +\& +\& my_eval_sv(command, TRUE); +\& SvREFCNT_dec(command); +\& +\& *match_list = get_av("array", 0); +\& num_matches = av_top_index(*match_list) + 1; +\& +\& return num_matches; +\& } +\& +\& main (int argc, char **argv, char **env) +\& { +\& char *embedding[] = { "", "\-e", "0", NULL }; +\& AV *match_list; +\& I32 num_matches, i; +\& SV *text; +\& +\& PERL_SYS_INIT3(&argc,&argv,&env); +\& my_perl = perl_alloc(); +\& perl_construct(my_perl); +\& perl_parse(my_perl, NULL, 3, embedding, NULL); +\& PL_exit_flags |= PERL_EXIT_DESTRUCT_END; +\& +\& text = newSV(0); +\& sv_setpv(text, "When he is at a convenience store and the " +\& "bill comes to some amount like 76 cents, Maynard is " +\& "aware that there is something he *should* do, something " +\& "that will enable him to get back a quarter, but he has " +\& "no idea *what*. He fumbles through his red squeezey " +\& "changepurse and gives the boy three extra pennies with " +\& "his dollar, hoping that he might luck into the correct " +\& "amount. The boy gives him back two of his own pennies " +\& "and then the big shiny quarter that is his prize. " +\& "\-RICHH"); +\& +\& if (match(text, "m/quarter/")) /** Does text contain \*(Aqquarter\*(Aq? **/ +\& printf("match: Text contains the word \*(Aqquarter\*(Aq.\en\en"); +\& else +\& printf("match: Text doesn\*(Aqt contain the word \*(Aqquarter\*(Aq.\en\en"); +\& +\& if (match(text, "m/eighth/")) /** Does text contain \*(Aqeighth\*(Aq? **/ +\& printf("match: Text contains the word \*(Aqeighth\*(Aq.\en\en"); +\& else +\& printf("match: Text doesn\*(Aqt contain the word \*(Aqeighth\*(Aq.\en\en"); +\& +\& /** Match all occurrences of /wi../ **/ +\& num_matches = matches(text, "m/(wi..)/g", &match_list); +\& printf("matches: m/(wi..)/g found %d matches...\en", num_matches); +\& +\& for (i = 0; i < num_matches; i++) +\& printf("match: %s\en", +\& SvPV_nolen(*av_fetch(match_list, i, FALSE))); +\& printf("\en"); +\& +\& /** Remove all vowels from text **/ +\& num_matches = substitute(&text, "s/[aeiou]//gi"); +\& if (num_matches) { +\& printf("substitute: s/[aeiou]//gi...%lu substitutions made.\en", +\& (unsigned long)num_matches); +\& printf("Now text is: %s\en\en", SvPV_nolen(text)); +\& } +\& +\& /** Attempt a substitution **/ +\& if (!substitute(&text, "s/Perl/C/")) { +\& printf("substitute: s/Perl/C...No substitution made.\en\en"); +\& } +\& +\& SvREFCNT_dec(text); +\& PL_perl_destruct_level = 1; +\& perl_destruct(my_perl); +\& perl_free(my_perl); +\& PERL_SYS_TERM(); +\& } +.Ve +.PP +which produces the output (again, long lines have been wrapped here) +.PP +.Vb 1 +\& match: Text contains the word \*(Aqquarter\*(Aq. +\& +\& match: Text doesn\*(Aqt contain the word \*(Aqeighth\*(Aq. +\& +\& matches: m/(wi..)/g found 2 matches... +\& match: will +\& match: with +\& +\& substitute: s/[aeiou]//gi...139 substitutions made. +\& Now text is: Whn h s t cnvnnc str nd th bll cms t sm mnt lk 76 cnts, +\& Mynrd s wr tht thr s smthng h *shld* d, smthng tht wll nbl hm t gt +\& bck qrtr, bt h hs n d *wht*. H fmbls thrgh hs rd sqzy chngprs nd +\& gvs th by thr xtr pnns wth hs dllr, hpng tht h mght lck nt th crrct +\& mnt. Th by gvs hm bck tw f hs wn pnns nd thn th bg shny qrtr tht s +\& hs prz. \-RCHH +\& +\& substitute: s/Perl/C...No substitution made. +.Ve +.SS "Fiddling with the Perl stack from your C program" +.IX Subsection "Fiddling with the Perl stack from your C program" +When trying to explain stacks, most computer science textbooks mumble +something about spring-loaded columns of cafeteria plates: the last +thing you pushed on the stack is the first thing you pop off. That'll +do for our purposes: your C program will push some arguments onto "the Perl +stack", shut its eyes while some magic happens, and then pop the +results\-\-the return value of your Perl subroutine\-\-off the stack. +.PP +First you'll need to know how to convert between C types and Perl +types, with \fBnewSViv()\fR and \fBsv_setnv()\fR and \fBnewAV()\fR and all their +friends. They're described in perlguts and perlapi. +.PP +Then you'll need to know how to manipulate the Perl stack. That's +described in perlcall. +.PP +Once you've understood those, embedding Perl in C is easy. +.PP +Because C has no builtin function for integer exponentiation, let's +make Perl's ** operator available to it (this is less useful than it +sounds, because Perl implements ** with C's \fR\f(BIpow()\fR\fI\fR function). First +I'll create a stub exponentiation function in \fIpower.pl\fR: +.PP +.Vb 4 +\& sub expo { +\& my ($a, $b) = @_; +\& return $a ** $b; +\& } +.Ve +.PP +Now I'll create a C program, \fIpower.c\fR, with a function +\&\fR\f(BIPerlPower()\fR\fI\fR that contains all the perlguts necessary to push the +two arguments into \fI\fR\f(BIexpo()\fR\fI\fR and to pop the return value out. Take a +deep breath... +.PP +.Vb 2 +\& #include +\& #include +\& +\& static PerlInterpreter *my_perl; +\& +\& static void +\& PerlPower(int a, int b) +\& { +\& dSP; /* initialize stack pointer */ +\& ENTER; /* everything created after here */ +\& SAVETMPS; /* ...is a temporary variable. */ +\& PUSHMARK(SP); /* remember the stack pointer */ +\& XPUSHs(sv_2mortal(newSViv(a))); /* push the base onto the stack */ +\& XPUSHs(sv_2mortal(newSViv(b))); /* push the exponent onto stack */ +\& PUTBACK; /* make local stack pointer global */ +\& call_pv("expo", G_SCALAR); /* call the function */ +\& SPAGAIN; /* refresh stack pointer */ +\& /* pop the return value from stack */ +\& printf ("%d to the %dth power is %d.\en", a, b, POPi); +\& PUTBACK; +\& FREETMPS; /* free that return value */ +\& LEAVE; /* ...and the XPUSHed "mortal" args.*/ +\& } +\& +\& int main (int argc, char **argv, char **env) +\& { +\& char *my_argv[] = { "", "power.pl", NULL }; +\& +\& PERL_SYS_INIT3(&argc,&argv,&env); +\& my_perl = perl_alloc(); +\& perl_construct( my_perl ); +\& +\& perl_parse(my_perl, NULL, 2, my_argv, (char **)NULL); +\& PL_exit_flags |= PERL_EXIT_DESTRUCT_END; +\& perl_run(my_perl); +\& +\& PerlPower(3, 4); /*** Compute 3 ** 4 ***/ +\& +\& perl_destruct(my_perl); +\& perl_free(my_perl); +\& PERL_SYS_TERM(); +\& exit(EXIT_SUCCESS); +\& } +.Ve +.PP +Compile and run: +.PP +.Vb 1 +\& % cc \-o power power.c \`perl \-MExtUtils::Embed \-e ccopts \-e ldopts\` +\& +\& % power +\& 3 to the 4th power is 81. +.Ve +.SS "Maintaining a persistent interpreter" +.IX Subsection "Maintaining a persistent interpreter" +When developing interactive and/or potentially long-running +applications, it's a good idea to maintain a persistent interpreter +rather than allocating and constructing a new interpreter multiple +times. The major reason is speed: since Perl will only be loaded into +memory once. +.PP +However, you have to be more cautious with namespace and variable +scoping when using a persistent interpreter. In previous examples +we've been using global variables in the default package \f(CW\*(C`main\*(C'\fR. We +knew exactly what code would be run, and assumed we could avoid +variable collisions and outrageous symbol table growth. +.PP +Let's say your application is a server that will occasionally run Perl +code from some arbitrary file. Your server has no way of knowing what +code it's going to run. Very dangerous. +.PP +If the file is pulled in by \f(CWperl_parse()\fR, compiled into a newly +constructed interpreter, and subsequently cleaned out with +\&\f(CWperl_destruct()\fR afterwards, you're shielded from most namespace +troubles. +.PP +One way to avoid namespace collisions in this scenario is to translate +the filename into a guaranteed-unique package name, and then compile +the code into that package using "eval" in perlfunc. In the example +below, each file will only be compiled once. Or, the application +might choose to clean out the symbol table associated with the file +after it's no longer needed. Using "call_argv" in perlapi, We'll +call the subroutine \f(CW\*(C`Embed::Persistent::eval_file\*(C'\fR which lives in the +file \f(CW\*(C`persistent.pl\*(C'\fR and pass the filename and boolean cleanup/cache +flag as arguments. +.PP +Note that the process will continue to grow for each file that it +uses. In addition, there might be \f(CW\*(C`AUTOLOAD\*(C'\fRed subroutines and other +conditions that cause Perl's symbol table to grow. You might want to +add some logic that keeps track of the process size, or restarts +itself after a certain number of requests, to ensure that memory +consumption is minimized. You'll also want to scope your variables +with "my" in perlfunc whenever possible. +.PP +.Vb 2 +\& package Embed::Persistent; +\& #persistent.pl +\& +\& use strict; +\& our %Cache; +\& use Symbol qw(delete_package); +\& +\& sub valid_package_name { +\& my($string) = @_; +\& $string =~ s/([^A\-Za\-z0\-9\e/])/sprintf("_%2x",unpack("C",$1))/eg; +\& # second pass only for words starting with a digit +\& $string =~ s|/(\ed)|sprintf("/_%2x",unpack("C",$1))|eg; +\& +\& # Dress it up as a real package name +\& $string =~ s|/|::|g; +\& return "Embed" . $string; +\& } +\& +\& sub eval_file { +\& my($filename, $delete) = @_; +\& my $package = valid_package_name($filename); +\& my $mtime = \-M $filename; +\& if(defined $Cache{$package}{mtime} +\& && +\& $Cache{$package}{mtime} <= $mtime) +\& { +\& # we have compiled this subroutine already, +\& # it has not been updated on disk, nothing left to do +\& print STDERR "already compiled $package\->handler\en"; +\& } +\& else { +\& local *FH; +\& open FH, $filename or die "open \*(Aq$filename\*(Aq $!"; +\& local($/) = undef; +\& my $sub = ; +\& close FH; +\& +\& #wrap the code into a subroutine inside our unique package +\& my $eval = qq{package $package; sub handler { $sub; }}; +\& { +\& # hide our variables within this block +\& my($filename,$mtime,$package,$sub); +\& eval $eval; +\& } +\& die $@ if $@; +\& +\& #cache it unless we\*(Aqre cleaning out each time +\& $Cache{$package}{mtime} = $mtime unless $delete; +\& } +\& +\& eval {$package\->handler;}; +\& die $@ if $@; +\& +\& delete_package($package) if $delete; +\& +\& #take a look if you want +\& #print Devel::Symdump\->rnew($package)\->as_string, $/; +\& } +\& +\& 1; +\& +\& _\|_END_\|_ +\& +\& /* persistent.c */ +\& #include +\& #include +\& +\& /* 1 = clean out filename\*(Aqs symbol table after each request, +\& 0 = don\*(Aqt +\& */ +\& #ifndef DO_CLEAN +\& #define DO_CLEAN 0 +\& #endif +\& +\& #define BUFFER_SIZE 1024 +\& +\& static PerlInterpreter *my_perl = NULL; +\& +\& int +\& main(int argc, char **argv, char **env) +\& { +\& char *embedding[] = { "", "persistent.pl", NULL }; +\& char *args[] = { "", DO_CLEAN, NULL }; +\& char filename[BUFFER_SIZE]; +\& int failing, exitstatus; +\& +\& PERL_SYS_INIT3(&argc,&argv,&env); +\& if((my_perl = perl_alloc()) == NULL) { +\& fprintf(stderr, "no memory!"); +\& exit(EXIT_FAILURE); +\& } +\& perl_construct(my_perl); +\& +\& PL_origalen = 1; /* don\*(Aqt let $0 assignment update the +\& proctitle or embedding[0] */ +\& failing = perl_parse(my_perl, NULL, 2, embedding, NULL); +\& PL_exit_flags |= PERL_EXIT_DESTRUCT_END; +\& if(!failing) +\& failing = perl_run(my_perl); +\& if(!failing) { +\& while(printf("Enter file name: ") && +\& fgets(filename, BUFFER_SIZE, stdin)) { +\& +\& filename[strlen(filename)\-1] = \*(Aq\e0\*(Aq; /* strip \en */ +\& /* call the subroutine, +\& passing it the filename as an argument */ +\& args[0] = filename; +\& call_argv("Embed::Persistent::eval_file", +\& G_DISCARD | G_EVAL, args); +\& +\& /* check $@ */ +\& if(SvTRUE(ERRSV)) +\& fprintf(stderr, "eval error: %s\en", SvPV_nolen(ERRSV)); +\& } +\& } +\& +\& PL_perl_destruct_level = 0; +\& exitstatus = perl_destruct(my_perl); +\& perl_free(my_perl); +\& PERL_SYS_TERM(); +\& exit(exitstatus); +\& } +.Ve +.PP +Now compile: +.PP +.Vb 2 +\& % cc \-o persistent persistent.c \e +\& \`perl \-MExtUtils::Embed \-e ccopts \-e ldopts\` +.Ve +.PP +Here's an example script file: +.PP +.Vb 3 +\& #test.pl +\& my $string = "hello"; +\& foo($string); +\& +\& sub foo { +\& print "foo says: @_\en"; +\& } +.Ve +.PP +Now run: +.PP +.Vb 7 +\& % persistent +\& Enter file name: test.pl +\& foo says: hello +\& Enter file name: test.pl +\& already compiled Embed::test_2epl\->handler +\& foo says: hello +\& Enter file name: ^C +.Ve +.SS "Execution of END blocks" +.IX Subsection "Execution of END blocks" +Traditionally END blocks have been executed at the end of the perl_run. +This causes problems for applications that never call perl_run. Since +perl 5.7.2 you can specify \f(CW\*(C`PL_exit_flags |= PERL_EXIT_DESTRUCT_END\*(C'\fR +to get the new behaviour. This also enables the running of END blocks if +the perl_parse fails and \f(CW\*(C`perl_destruct\*(C'\fR will return the exit value. +.ie n .SS "$0 assignments" +.el .SS "\f(CW$0\fP assignments" +.IX Subsection "$0 assignments" +When a perl script assigns a value to \f(CW$0\fR then the perl runtime will +try to make this value show up as the program name reported by "ps" by +updating the memory pointed to by the argv passed to \fBperl_parse()\fR and +also calling API functions like \fBsetproctitle()\fR where available. This +behaviour might not be appropriate when embedding perl and can be +disabled by assigning the value \f(CW1\fR to the variable \f(CW\*(C`PL_origalen\*(C'\fR +before \fBperl_parse()\fR is called. +.PP +The \fIpersistent.c\fR example above is for instance likely to segfault +when \f(CW$0\fR is assigned to if the \f(CW\*(C`PL_origalen = 1;\*(C'\fR assignment is +removed. This because perl will try to write to the read only memory +of the \f(CW\*(C`embedding[]\*(C'\fR strings. +.SS "Maintaining multiple interpreter instances" +.IX Subsection "Maintaining multiple interpreter instances" +Some rare applications will need to create more than one interpreter +during a session. Such an application might sporadically decide to +release any resources associated with the interpreter. +.PP +The program must take care to ensure that this takes place \fIbefore\fR +the next interpreter is constructed. By default, when perl is not +built with any special options, the global variable +\&\f(CW\*(C`PL_perl_destruct_level\*(C'\fR is set to \f(CW0\fR, since extra cleaning isn't +usually needed when a program only ever creates a single interpreter +in its entire lifetime. +.PP +Setting \f(CW\*(C`PL_perl_destruct_level\*(C'\fR to \f(CW1\fR makes everything squeaky clean: +.PP +.Vb 10 +\& while(1) { +\& ... +\& /* reset global variables here with PL_perl_destruct_level = 1 */ +\& PL_perl_destruct_level = 1; +\& perl_construct(my_perl); +\& ... +\& /* clean and reset _everything_ during perl_destruct */ +\& PL_perl_destruct_level = 1; +\& perl_destruct(my_perl); +\& perl_free(my_perl); +\& ... +\& /* let\*(Aqs go do it again! */ +\& } +.Ve +.PP +When \fR\f(BIperl_destruct()\fR\fI\fR is called, the interpreter's syntax parse tree +and symbol tables are cleaned up, and global variables are reset. The +second assignment to \f(CW\*(C`PL_perl_destruct_level\*(C'\fR is needed because +perl_construct resets it to \f(CW0\fR. +.PP +Now suppose we have more than one interpreter instance running at the +same time. This is feasible, but only if you used the Configure option +\&\f(CW\*(C`\-Dusemultiplicity\*(C'\fR or the options \f(CW\*(C`\-Dusethreads \-Duseithreads\*(C'\fR when +building perl. By default, enabling one of these Configure options +sets the per-interpreter global variable \f(CW\*(C`PL_perl_destruct_level\*(C'\fR to +\&\f(CW1\fR, so that thorough cleaning is automatic and interpreter variables +are initialized correctly. Even if you don't intend to run two or +more interpreters at the same time, but to run them sequentially, like +in the above example, it is recommended to build perl with the +\&\f(CW\*(C`\-Dusemultiplicity\*(C'\fR option otherwise some interpreter variables may +not be initialized correctly between consecutive runs and your +application may crash. +.PP +See also "Thread-aware system interfaces" in perlxs. +.PP +Using \f(CW\*(C`\-Dusethreads \-Duseithreads\*(C'\fR rather than \f(CW\*(C`\-Dusemultiplicity\*(C'\fR +is more appropriate if you intend to run multiple interpreters +concurrently in different threads, because it enables support for +linking in the thread libraries of your system with the interpreter. +.PP +Let's give it a try: +.PP +.Vb 2 +\& #include +\& #include +\& +\& /* we\*(Aqre going to embed two interpreters */ +\& +\& #define SAY_HELLO "\-e", "print qq(Hi, I\*(Aqm $^X\en)" +\& +\& int main(int argc, char **argv, char **env) +\& { +\& PerlInterpreter *one_perl, *two_perl; +\& char *one_args[] = { "one_perl", SAY_HELLO, NULL }; +\& char *two_args[] = { "two_perl", SAY_HELLO, NULL }; +\& +\& PERL_SYS_INIT3(&argc,&argv,&env); +\& one_perl = perl_alloc(); +\& two_perl = perl_alloc(); +\& +\& PERL_SET_CONTEXT(one_perl); +\& perl_construct(one_perl); +\& PERL_SET_CONTEXT(two_perl); +\& perl_construct(two_perl); +\& +\& PERL_SET_CONTEXT(one_perl); +\& perl_parse(one_perl, NULL, 3, one_args, (char **)NULL); +\& PERL_SET_CONTEXT(two_perl); +\& perl_parse(two_perl, NULL, 3, two_args, (char **)NULL); +\& +\& PERL_SET_CONTEXT(one_perl); +\& perl_run(one_perl); +\& PERL_SET_CONTEXT(two_perl); +\& perl_run(two_perl); +\& +\& PERL_SET_CONTEXT(one_perl); +\& perl_destruct(one_perl); +\& PERL_SET_CONTEXT(two_perl); +\& perl_destruct(two_perl); +\& +\& PERL_SET_CONTEXT(one_perl); +\& perl_free(one_perl); +\& PERL_SET_CONTEXT(two_perl); +\& perl_free(two_perl); +\& PERL_SYS_TERM(); +\& exit(EXIT_SUCCESS); +\& } +.Ve +.PP +Note the calls to \fBPERL_SET_CONTEXT()\fR. These are necessary to initialize +the global state that tracks which interpreter is the "current" one on +the particular process or thread that may be running it. It should +always be used if you have more than one interpreter and are making +perl API calls on both interpreters in an interleaved fashion. +.PP +PERL_SET_CONTEXT(interp) should also be called whenever \f(CW\*(C`interp\*(C'\fR is +used by a thread that did not create it (using either \fBperl_alloc()\fR, or +the more esoteric \fBperl_clone()\fR). +.PP +Compile as usual: +.PP +.Vb 2 +\& % cc \-o multiplicity multiplicity.c \e +\& \`perl \-MExtUtils::Embed \-e ccopts \-e ldopts\` +.Ve +.PP +Run it, Run it: +.PP +.Vb 3 +\& % multiplicity +\& Hi, I\*(Aqm one_perl +\& Hi, I\*(Aqm two_perl +.Ve +.SS "Using Perl modules, which themselves use C libraries, from your C program" +.IX Subsection "Using Perl modules, which themselves use C libraries, from your C program" +If you've played with the examples above and tried to embed a script +that \fR\f(BIuse()\fR\fI\fRs a Perl module (such as \fISocket\fR) which itself uses a C or C++ +library, this probably happened: +.PP +.Vb 3 +\& Can\*(Aqt load module Socket, dynamic loading not available in this perl. +\& (You may need to build a new perl executable which either supports +\& dynamic loading or has the Socket module statically linked into it.) +.Ve +.PP +What's wrong? +.PP +Your interpreter doesn't know how to communicate with these extensions +on its own. A little glue will help. Up until now you've been +calling \fR\f(BIperl_parse()\fR\fI\fR, handing it NULL for the second argument: +.PP +.Vb 1 +\& perl_parse(my_perl, NULL, argc, my_argv, NULL); +.Ve +.PP +That's where the glue code can be inserted to create the initial contact +between Perl and linked C/C++ routines. Let's take a look some pieces of +\&\fIperlmain.c\fR to see how Perl does this: +.PP +.Vb 1 +\& static void xs_init (pTHX); +\& +\& EXTERN_C void boot_DynaLoader (pTHX_ CV* cv); +\& EXTERN_C void boot_Socket (pTHX_ CV* cv); +\& +\& +\& EXTERN_C void +\& xs_init(pTHX) +\& { +\& char *file = _\|_FILE_\|_; +\& /* DynaLoader is a special case */ +\& newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file); +\& newXS("Socket::bootstrap", boot_Socket, file); +\& } +.Ve +.PP +Simply put: for each extension linked with your Perl executable +(determined during its initial configuration on your +computer or when adding a new extension), +a Perl subroutine is created to incorporate the extension's +routines. Normally, that subroutine is named +\&\fR\f(BIModule::bootstrap()\fR\fI\fR and is invoked when you say \fIuse Module\fR. In +turn, this hooks into an XSUB, \fIboot_Module\fR, which creates a Perl +counterpart for each of the extension's XSUBs. Don't worry about this +part; leave that to the \fIxsubpp\fR and extension authors. If your +extension is dynamically loaded, DynaLoader creates \fI\fR\f(BIModule::bootstrap()\fR\fI\fR +for you on the fly. In fact, if you have a working DynaLoader then there +is rarely any need to link in any other extensions statically. +.PP +Once you have this code, slap it into the second argument of \fR\f(BIperl_parse()\fR\fI\fR: +.PP +.Vb 1 +\& perl_parse(my_perl, xs_init, argc, my_argv, NULL); +.Ve +.PP +Then compile: +.PP +.Vb 1 +\& % cc \-o interp interp.c \`perl \-MExtUtils::Embed \-e ccopts \-e ldopts\` +\& +\& % interp +\& use Socket; +\& use SomeDynamicallyLoadedModule; +\& +\& print "Now I can use extensions!\en"\*(Aq +.Ve +.PP +\&\fBExtUtils::Embed\fR can also automate writing the \fIxs_init\fR glue code. +.PP +.Vb 4 +\& % perl \-MExtUtils::Embed \-e xsinit \-\- \-o perlxsi.c +\& % cc \-c perlxsi.c \`perl \-MExtUtils::Embed \-e ccopts\` +\& % cc \-c interp.c \`perl \-MExtUtils::Embed \-e ccopts\` +\& % cc \-o interp perlxsi.o interp.o \`perl \-MExtUtils::Embed \-e ldopts\` +.Ve +.PP +Consult perlxs, perlguts, and perlapi for more details. +.SS "Using embedded Perl with POSIX locales" +.IX Subsection "Using embedded Perl with POSIX locales" +(See perllocale for information about these.) +When a Perl interpreter normally starts up, it tells the system it wants +to use the system's default locale. This is often, but not necessarily, +the "C" or "POSIX" locale. Absent a \f(CW"use\ locale"\fR within the perl +code, this mostly has no effect (but see "Not within the +scope of "use locale"" in perllocale). Also, there is not a problem if the +locale you want to use in your embedded perl is the same as the system +default. However, this doesn't work if you have set up and want to use +a locale that isn't the system default one. Starting in Perl v5.20, you +can tell the embedded Perl interpreter that the locale is already +properly set up, and to skip doing its own normal initialization. It +skips if the environment variable \f(CW\*(C`PERL_SKIP_LOCALE_INIT\*(C'\fR is set (even +if set to 0 or \f(CW""\fR). A perl that has this capability will define the +C pre-processor symbol \f(CW\*(C`HAS_SKIP_LOCALE_INIT\*(C'\fR. This allows code that +has to work with multiple Perl versions to do some sort of work-around +when confronted with an earlier Perl. +.PP +If your program is using the POSIX 2008 multi-thread locale +functionality, you should switch into the global locale and set that up +properly before starting the Perl interpreter. It will then properly +switch back to using the thread-safe functions. +.SH "Hiding Perl_" +.IX Header "Hiding Perl_" +If you completely hide the short forms of the Perl public API, +add \-DPERL_NO_SHORT_NAMES to the compilation flags. This means that +for example instead of writing +.PP +.Vb 1 +\& warn("%d bottles of beer on the wall", bottlecount); +.Ve +.PP +you will have to write the explicit full form +.PP +.Vb 1 +\& Perl_warn(aTHX_ "%d bottles of beer on the wall", bottlecount); +.Ve +.PP +(See "Background and MULTIPLICITY" in perlguts for the explanation +of the \f(CW\*(C`aTHX_\*(C'\fR. ) Hiding the short forms is very useful for avoiding +all sorts of nasty (C preprocessor or otherwise) conflicts with other +software packages (Perl defines about 2400 APIs with these short names, +take or leave few hundred, so there certainly is room for conflict.) +.SH MORAL +.IX Header "MORAL" +You can sometimes \fIwrite faster code\fR in C, but +you can always \fIwrite code faster\fR in Perl. Because you can use +each from the other, combine them as you wish. +.SH AUTHOR +.IX Header "AUTHOR" +Jon Orwant <\fIorwant@media.mit.edu\fR> and Doug MacEachern +<\fIdougm@covalent.net\fR>, with small contributions from Tim Bunce, Tom +Christiansen, Guy Decoux, Hallvard Furuseth, Dov Grobgeld, and Ilya +Zakharevich. +.PP +Doug MacEachern has an article on embedding in Volume 1, Issue 4 of +The Perl Journal ( ). Doug is also the developer of the +most widely-used Perl embedding: the mod_perl system +(perl.apache.org), which embeds Perl in the Apache web server. +Oracle, Binary Evolution, ActiveState, and Ben Sugars's nsapi_perl +have used this model for Oracle, Netscape and Internet Information +Server Perl plugins. +.SH COPYRIGHT +.IX Header "COPYRIGHT" +Copyright (C) 1995, 1996, 1997, 1998 Doug MacEachern and Jon Orwant. All +Rights Reserved. +.PP +This document may be distributed under the same terms as Perl itself. -- cgit v1.2.3