[30369] in Perl-Users-Digest

home help back first fref pref prev next nref lref last post

Perl-Users Digest, Issue: 1612 Volume: 11

daemon@ATHENA.MIT.EDU (Perl-Users Digest)
Thu Jun 5 00:14:26 2008

Date: Wed, 4 Jun 2008 21:14:17 -0700 (PDT)
From: Perl-Users Digest <Perl-Users-Request@ruby.OCE.ORST.EDU>
To: Perl-Users@ruby.OCE.ORST.EDU (Perl-Users Digest)

Perl-Users Digest           Wed, 4 Jun 2008     Volume: 11 Number: 1612

Today's topics:
        Questions about "perldoc perlembed" <jl_post@hotmail.com>
    Re: Questions about "perldoc perlembed" <ben@morrow.me.uk>
    Re: Questions about "perldoc perlembed" <sisyphus359@gmail.com>
        recursive perl? <workitharder@gmail.com>
        RHS of s/LHS/RHS/ with $1, $2, etc. without "eval"? (Ben Bullock)
    Re: RHS of s/LHS/RHS/ with $1, $2, etc. without "eval"? <tadmc@seesig.invalid>
    Re: RHS of s/LHS/RHS/ with $1, $2, etc. without "eval"? <noreply@gunnar.cc>
    Re: RHS of s/LHS/RHS/ with $1, $2, etc. without "eval"? <mjcarman@mchsi.com>
        Stopping a File::Find on first find Mason.Guy@gmail.com
    Re: Stopping a File::Find on first find <ben@morrow.me.uk>
    Re: Stopping a File::Find on first find <jl_post@hotmail.com>
    Re: XML::Parser Tree Style <tadmc@seesig.invalid>
        Digest Administrivia (Last modified: 6 Apr 01) (Perl-Users-Digest Admin)

----------------------------------------------------------------------

Date: Wed, 4 Jun 2008 14:02:24 -0700 (PDT)
From: "jl_post@hotmail.com" <jl_post@hotmail.com>
Subject: Questions about "perldoc perlembed"
Message-Id: <6207c641-fe06-4053-8f3c-000dc2846044@x41g2000hsb.googlegroups.com>

Hi,

   Ultimately I am trying to embed the ability to run Perl scripts on
a C++ program written in Visual Studio 2005 (on a Windows XP
machine).  I have read "perldoc perlembed" and I have followed along
by running several of its examples on a Linux platform.  While I can
get the sample programs to work on Linux, I am stumbling on getting
Perl to properly embed in my Win32 C++ program.

   So I have a bunch of questions to ask about some of the concepts in
"perlembed".  I'm hoping that with the answers to my questions I might
be able to resolve my issues.

Issue 1:  "perlembed" gives the following warning:

   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.)

Now, I was able to compile Perl by downloading AP1003_source.zip from
ActiveState, unzipping it, cd-ing to perl/win32 and typing "nmake".
What confuses me is that this is not the same way I compile my main C+
+ program.  In Visual Studio, I normally load a *.sln or *.vcproj file
and compile it from there, never using nmake or a Unix-like Makefile.
Therefore, I can't quite figure out how to compile both perl and my C+
+ program with the same options.

So question 1 is:  How do I compile both Perl and my C++ program "in
exactly the same way"?

Issue 2:  "perlembed" gives a wonderful example program that
demonstrates how to run/evaluate Perl statements from a C program
(header comments are mine):
/* From "perldoc perlembed" */
/* Compile on Unix with:
    cc -o perl_eg1 perl_eg1.c `perl -MExtUtils::Embed -e ccopts -e
ldopts`
 */

#include <EXTERN.h>
#include <perl.h>

static PerlInterpreter *my_perl;

main (int argc, char **argv, char **env)
{
    STRLEN n_a;
    char *embedding[] = { "", "-e", "0" };

    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\n", SvIV(get_sv("a", FALSE)));

    /** Treat $a as a float **/
    eval_pv("$a = 3.14; $a **= 2", TRUE);
    printf("a = %f\n", SvNV(get_sv("a", FALSE)));

    /** Treat $a as a string **/
    eval_pv("$a = 'rekcaH lreP rehtonA tsuJ'; $a = reverse($a);",
TRUE);
    printf("a = %s\n", SvPV(get_sv("a", FALSE), n_a));

    perl_destruct(my_perl);
    perl_free(my_perl);
    PERL_SYS_TERM();
}

I was curious to see how calls to eval_pv() knew which PerlInterpreter
to use, so I changed all instances of "my_perl" to "my__perl" (note
the double underscores).  But when I tried to compile the program, I
got the following compiler error:

perl_eg1.c: In function `main':
perl_eg1.c:21: error: `my_perl' undeclared

I thought that was odd... Of course 'my_perl' is undeclared -- it's
'my__perl' that I want it to use.  But for some reason, the
"PL_exit_flags |= PERL_EXIT_DESTRUCT_END;" line wants to use
'my_perl', whether it was declared or not.  (Incidentally, I tried
commenting out that line to see what would happen, and the compiler
gave the same complaint for line 25, which is the ' eval_pv("$a = 3;
$a **= 2", TRUE);' line.)

So evidently, PL_exit_flags and eval_pv() want to use a
PerlInterpreter named "my_perl".  But declaring a static/global
variable like in the given example won't work too well with threads,
if I ever have to run two (or more) scripts concurrently.  So I
thought about how to get around this "my_perl" naming requirement.

Eventually I read the section "Maintaining multiple interpreter
instances" (also in "perlembed") which talks about
PERL_SET_CONTEXT().  It says that that call is "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."

Sounds good.  It seems like I all have to do is call
PERL_SET_CONTEXT(my__perl) for the compiler to stop looking for
"my_perl".  So I put "PERL_SET_CONTEXT(my__perl);" line right before
the perl_construct(), perl_parse(), PL_exit_flags, and all the
eval_pv() lines, but it doesn't appear to do any good.  The compiler
still complains that "my_perl" in undeclared at the PL_exit_flags and
eval_pv() lines.

So question 2 is:  Can calls to eval_pv() only be done when the
PerlInterpreter is specifically named "my_perl"?  (And if not, how can
I specify a differently-named PerlInterpreter?)

Issue 3:  I'm actually able to get a simple Perl program to run from
my C++ program with the following code:

void runPerlScript(char * script_filename)
{
  char* argv[] = { "PROGRAM_NAME" };
  int argc = sizeof(argv) / sizeof(char*);
  PERL_SYS_INIT3(&argc, NULL, NULL);

  PerlInterpreter *perlInterpreter = perl_alloc();

  char* scriptArguments[] = { "PROGRAM_NAME",
                                "-ID:/perl/lib",
                              script_filename };
  const int numArguments = sizeof(scriptArguments) / sizeof(char*);

  PERL_SET_CONTEXT(perlInterpreter);  // is this line needed?
  PL_perl_destruct_level = 1;
  perl_construct(perlInterpreter);

  const int parseResult = perl_parse(perlInterpreter, NULL,
          numArguments, scriptArguments, (char**) NULL);
  if (parseResult == 0)
    perl_run(perlInterpreter);

  perl_destruct(perlInterpreter);
  perl_free(perlInterpreter);

  PERL_SYS_TERM();
}

With this code, I can run a simple script whose filename is passed in
as script_filename.  However, it only succeeds once.  The second time
this function is called, it crashes at the call to perl_parse().

I couldn't figure out what was causing this crash, but I read
something that seemed useful (again in "perlembed"), which said:

   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 -Dusemultiplicity option otherwise some
   interpreter variables may not be initialized correctly
   between consecutive runs and your application may
   crash.

Sounds like my problem!  So I go over to the perl/win32 directory and
have a look at its Makefile.  Inside it I see the following lines:

#
# uncomment to enable multiple interpreters.  This is need
# for fork() emulation and for thread support.
#
USE_MULTI	= define

and the lines:

CFG_VARS	=					\
		"INST_DRV=$(INST_DRV)"			\
   .
   .
   .
		"usemultiplicity=$(USE_MULTI)"		\
   .
   .
   .
		"optimize=$(OPTIMIZE:"=\")"

As far as I can tell, the "usemultiplicity" option is indeed being
used when compiling.  Because of this, I can't figure out why the
second call to perl_parse() is crashing.

So Question 3 is:  Why is my C++ program crashing the second time it
calls perl_parse()?  (Is it because the -Dusemultiplicity option
wasn't set correctly, and if so, how do I set it correctly?)

Issue 4:  I am able to "use" certain simple modules in my Perl scripts
that are run from the C++ program (like "warnigns" and "Time::Local"),
but not ones that have dynamic loading (like "Data::Dumper").  There
is a section in "perldoc perlembed" that addresses this very issue,
and it provides this sample solution for "use"ing the Socket module:

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);
}

So Question 4a is:  That's nice for Socket, but how would I
incorporate a module name with "::" in it, like "Data::Dumper"?  I
can't just add the line:

   newXS("Data::Dumper::bootstrap", boot_Data::Dumper, file);

I would think that the "::" (outside of the string) would cause a
compiler error.

And Question 4b is:  Do I have to hard-code the inclusion of every
dynamic module I would ever want to use?  (Since the example does it
for the Socket module, it seems as though I would have to.)

   Thanks in advance for any help.

   -- Jean-Luc


------------------------------

Date: Wed, 4 Jun 2008 23:32:26 +0100
From: Ben Morrow <ben@morrow.me.uk>
Subject: Re: Questions about "perldoc perlembed"
Message-Id: <qohjh5-oh41.ln1@osiris.mauzo.dyndns.org>


Quoth "jl_post@hotmail.com" <jl_post@hotmail.com>:
> 
>    Ultimately I am trying to embed the ability to run Perl scripts on
> a C++ program written in Visual Studio 2005 (on a Windows XP
> machine).

Good luck... this stuff is Not Easy.

> I have read "perldoc perlembed" and I have followed along
> by running several of its examples on a Linux platform.  While I can
> get the sample programs to work on Linux, I am stumbling on getting
> Perl to properly embed in my Win32 C++ program.
> 
>    So I have a bunch of questions to ask about some of the concepts in
> "perlembed".  I'm hoping that with the answers to my questions I might
> be able to resolve my issues.
> 
> Issue 1:  "perlembed" gives the following warning:
> 
>    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.)
> 
> Now, I was able to compile Perl by downloading AP1003_source.zip from
> ActiveState, unzipping it, cd-ing to perl/win32 and typing "nmake".
> What confuses me is that this is not the same way I compile my main C+
> + program.  In Visual Studio, I normally load a *.sln or *.vcproj file
> and compile it from there, never using nmake or a Unix-like Makefile.
> Therefore, I can't quite figure out how to compile both perl and my C+
> + program with the same options.
> 
> So question 1 is:  How do I compile both Perl and my C++ program "in
> exactly the same way"?

Your comment below says how: use ExtUtils::Embed. If you are using
ActivePerl sources, be very sure that VC++ is the only compiler in your
PATH: ActivePerl patch Config.pm to emit gcc syntax if gcc is in your
PATH. Also, make sure you are picking up the correct perl5*.dll: the
binary builds of AS Perl are built with MSVC6, and attempting to link
these with MSVC 2005 will cause C library runtime failures.

You need to pass the output of

    perl -MExtUtils::Embed -eccopts

to the 'cc -c' or equivalent ('cl /c'? I can't remember MSVC command-
line syntax) command, and the output of

    perl -MExtUtils::Embed -eldopts

to the link command. Somewhere in the VC gui there should be an option
to allow you to pass custom flags to the compiler and linker.

Also note that if you're compiling just one file, say test.c, then the
ccopts need to come *before* and the ldopts *after* test.c on the
command-line.

> Issue 2:  "perlembed" gives a wonderful example program that
> demonstrates how to run/evaluate Perl statements from a C program
> (header comments are mine):
<snip>
> 
> I was curious to see how calls to eval_pv() knew which PerlInterpreter
> to use, so I changed all instances of "my_perl" to "my__perl" (note
> the double underscores).  But when I tried to compile the program, I
> got the following compiler error:
> 
> perl_eg1.c: In function `main':
> perl_eg1.c:21: error: `my_perl' undeclared
> 
> I thought that was odd... Of course 'my_perl' is undeclared -- it's
> 'my__perl' that I want it to use.  But for some reason, the
> "PL_exit_flags |= PERL_EXIT_DESTRUCT_END;" line wants to use
> 'my_perl', whether it was declared or not.  (Incidentally, I tried
> commenting out that line to see what would happen, and the compiler
> gave the same complaint for line 25, which is the ' eval_pv("$a = 3;
> $a **= 2", TRUE);' line.)

Yup. If you root around in intrpvar.h and proto.h you'll find both
PL_exit_flags and eval_pv are #defined to expressions that include
my_perl. 

> So evidently, PL_exit_flags and eval_pv() want to use a
> PerlInterpreter named "my_perl".  But declaring a static/global
> variable like in the given example won't work too well with threads,
> if I ever have to run two (or more) scripts concurrently.  So I
> thought about how to get around this "my_perl" naming requirement.
> 
> Eventually I read the section "Maintaining multiple interpreter
> instances" (also in "perlembed") which talks about
> PERL_SET_CONTEXT().  It says that that call is "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."
> 
> Sounds good.  It seems like I all have to do is call
> PERL_SET_CONTEXT(my__perl) for the compiler to stop looking for
> "my_perl".  So I put "PERL_SET_CONTEXT(my__perl);" line right before
> the perl_construct(), perl_parse(), PL_exit_flags, and all the
> eval_pv() lines, but it doesn't appear to do any good.  The compiler
> still complains that "my_perl" in undeclared at the PL_exit_flags and
> eval_pv() lines.
> 
> So question 2 is:  Can calls to eval_pv() only be done when the
> PerlInterpreter is specifically named "my_perl"?  (And if not, how can
> I specify a differently-named PerlInterpreter?)

The simple answer is 'yes'. The most obvious way round it is to notice
what eval_pv expands to: in a perl built with MULTIPLICITY, it is
#defined (in embed.h) with

    #define eval_pv(a,b) Perl_eval_pv(aTHX_ a, b)

and aTHX_ is

    #define aTHX_ my_perl,

 . So in MULTIPLICITY perls, Perl_eval_pv takes an extra first parameter
which is a PerlInterpreter*, and you can pass your own my__perl instead.

Another option, of course, is to keep a 'my_perl' variable around, and
switch which interpreter it points to.

I don't know if this is the 'correct' answer: you might want to take a
look at what the users of MULTIPLICITY--mod_perl and threads.xs, most
notably--do about it. Or you might want to ask p5p.

> Issue 3:  I'm actually able to get a simple Perl program to run from
> my C++ program with the following code:
> 
> void runPerlScript(char * script_filename)
> {
>   char* argv[] = { "PROGRAM_NAME" };
>   int argc = sizeof(argv) / sizeof(char*);
>   PERL_SYS_INIT3(&argc, NULL, NULL);

You may only call PERL_SYS_INIT3 once, ever. Call it in main().

>   PerlInterpreter *perlInterpreter = perl_alloc();
> 
>   char* scriptArguments[] = { "PROGRAM_NAME",
>                                 "-ID:/perl/lib",
>                               script_filename };
>   const int numArguments = sizeof(scriptArguments) / sizeof(char*);
> 
>   PERL_SET_CONTEXT(perlInterpreter);  // is this line needed?
>   PL_perl_destruct_level = 1;

I'm surprised this line compiles. I would have expected all the PL_*
globals to expand to something that referenced 'my_perl'.

>   perl_construct(perlInterpreter);
> 
>   const int parseResult = perl_parse(perlInterpreter, NULL,
>           numArguments, scriptArguments, (char**) NULL);
>   if (parseResult == 0)
>     perl_run(perlInterpreter);
> 
>   perl_destruct(perlInterpreter);
>   perl_free(perlInterpreter);
> 
>   PERL_SYS_TERM();

Ditto PERL_SYS_TERM: only call it once, just before program exit.

[-Dusemultiplicity on Win32]
> #
> # uncomment to enable multiple interpreters.  This is need
> # for fork() emulation and for thread support.
> #
> USE_MULTI	= define
> 
> As far as I can tell, the "usemultiplicity" option is indeed being
> used when compiling.  Because of this, I can't figure out why the
> second call to perl_parse() is crashing.

Yes, all AS Perl builds have both usethreads and usemultiplicity set
(these are the defaults on vanilla Win32 builds anyway).

> So Question 3 is:  Why is my C++ program crashing the second time it
> calls perl_parse()?  (Is it because the -Dusemultiplicity option
> wasn't set correctly, and if so, how do I set it correctly?)

I suspect it's the PERL_SYS_{INIT3,TERM} stuff I mentioned above; if
not, then I don't know. Try p5p, and maybe build a debugging perl and
see if you can get a backtrace.

> Issue 4:  I am able to "use" certain simple modules in my Perl scripts
> that are run from the C++ program (like "warnigns" and "Time::Local"),
> but not ones that have dynamic loading (like "Data::Dumper").  There
> is a section in "perldoc perlembed" that addresses this very issue,
> and it provides this sample solution for "use"ing the Socket module:
> 
> 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);
> }
> 
> So Question 4a is:  That's nice for Socket, but how would I
> incorporate a module name with "::" in it, like "Data::Dumper"?  I
> can't just add the line:
> 
>    newXS("Data::Dumper::bootstrap", boot_Data::Dumper, file);
> 
> I would think that the "::" (outside of the string) would cause a
> compiler error.

Yup: you need to convert ':'s into '_'s, so you get boot_Data__Dumper.
Actually, you don't need to do this at all: xs_init only needs to load
bootstrap functions for extensions that are statically linked, which
nowadays is typically only DynaLoader. In any case, if you run

    perl -MExtUtils::Embed -exsinit

it will create a file called perlxsi.c with the appropriate definition
of xs_init in it. Compile that file, link it into your app, and call
xs_init at the right time.

> And Question 4b is:  Do I have to hard-code the inclusion of every
> dynamic module I would ever want to use?  (Since the example does it
> for the Socket module, it seems as though I would have to.)

No, only those linked statically. Since DynaLoader is always linked
statically, nothing else will work if you don't bootstrap DynaLoader;
but once that's there it takes care of all the dynamically-linked
extensions.

Once upon a time, when systems didn't tend to support dlopen as well as
they do now, it was common to link lots of extensions directly into
perl, which is why perlembed assumes that's what you might be doing.

Ben

-- 
For the last month, a large number of PSNs in the Arpa[Inter-]net have been
reporting symptoms of congestion ... These reports have been accompanied by an
increasing number of user complaints ... As of June,... the Arpanet contained
47 nodes and 63 links. [ftp://rtfm.mit.edu/pub/arpaprob.txt] * ben@morrow.me.uk


------------------------------

Date: Wed, 4 Jun 2008 15:49:00 -0700 (PDT)
From: sisyphus <sisyphus359@gmail.com>
Subject: Re: Questions about "perldoc perlembed"
Message-Id: <7ebe65b3-62fd-4c36-8b46-287d3e000eea@z24g2000prf.googlegroups.com>

On Jun 5, 7:02=A0am, "jl_p...@hotmail.com" <jl_p...@hotmail.com> wrote:
=2E
=2E
>
> So question 1 is: =A0How do I compile both Perl and my C++ program "in
> exactly the same way"?

The example you provided (eg1.c) compiles and runs fine for me (using
VC 7.0) - though it's a rather lengthy command line that I used.

The first part of the command is just:

cl eg1.c

To that, I appended the output of running:

perl -MExtUtils::Embed -e "ccopts"

And then I further appended with the output of running:

perl -MExtUtils::Embed -e "ldopts"

For me, somewhere in the ccopts/ldopts output, there was an "-
opt:ref,icf" switch which the compiler doesn't understand and which
needed to be removed from the command. I expect you would have to do
the same.

There were also some other switches in the command line that were not
understood, but they just produced the warning that they were being
ignored - which didn't seem to matter.

(I think the "exactly the same way" bit just means that you need to
provide the ccopts and ldopts for that particular build of perl. Both
ccopts and ldopts can vary from one build to another.)

Not sure if that helps. You said you've had some success, so perhaps
I'm only repeating what you already know.

> Sounds like my problem! =A0So I go over to the perl/win32 directory and
> have a look at its Makefile.

You could instead have examined the output of 'perl -V', or just run
'perl -V:usemultiplicity'.

Cheers,
Rob


------------------------------

Date: Wed, 4 Jun 2008 20:00:02 -0700 (PDT)
From: bukzor <workitharder@gmail.com>
Subject: recursive perl?
Message-Id: <84dad5a7-96ba-4507-ac55-867f6a9f2874@s50g2000hsb.googlegroups.com>

Here's what I'd like to do (unwise as it is) in a perl script:

1. pipe a perl script into a perl subprocess and capture the output
into a file (easy)
2. change the output of the perl subprocess to another file (also
easy: just pipe in an open(STDOUT, ">$file"))
3. Take the output of #1 and pipe that into the perl subprocess.

The problem is that perl waits for an end-of-file before starting
execution, so the output of #1 is not ready by the time I get to #3.
The main point of this is to preserve all the variables in perl's
memory on the second pass, so closing perl is not an option.

Is there a way to force perl to start executing before it gets to EOF?
I guesss I'm basically asking for an interactive mode...

Thanks!
--Buck


------------------------------

Date: Thu, 5 Jun 2008 01:49:59 +0000 (UTC)
From: benkasminbullock@gmail.com (Ben Bullock)
Subject: RHS of s/LHS/RHS/ with $1, $2, etc. without "eval"?
Message-Id: <g27go7$7eu$1@ml.accsnet.ne.jp>

The following script

#! perl -lw
use strict;
my ($text, $left, $right) = @ARGV[0..2];
my $text1 = $text;
$text1 =~ s/$left/$right/g;
print $text1;
my $text2 = $text;
eval ("\$text2 =~ s/$left/$right/g");
print $text2;

prints

$ ./substitute.pl monster '([aeiou])' 'X$1Y'
mX$1YnstX$1Yr
mXoYnstXeYr

Is there any way to get the substitution as in $text2 without using
eval?

Also, $& gives the value of what matched $left, but is there any
variable which gives the post-substitution value, that is the value of
$right after the $1, $2 substitutions has been performed?

Thank you for any assistance.


------------------------------

Date: Wed, 4 Jun 2008 22:37:38 -0500
From: Tad J McClellan <tadmc@seesig.invalid>
Subject: Re: RHS of s/LHS/RHS/ with $1, $2, etc. without "eval"?
Message-Id: <slrng4ens2.ghn.tadmc@tadmc30.sbcglobal.net>

Ben Bullock <benkasminbullock@gmail.com> wrote:
> The following script
>
> #! perl -lw
> use strict;
> my ($text, $left, $right) = @ARGV[0..2];
> my $text1 = $text;
> $text1 =~ s/$left/$right/g;
> print $text1;
> my $text2 = $text;
> eval ("\$text2 =~ s/$left/$right/g");


   $text2 =~ s/$left/$right/gee;


> print $text2;
>
> prints
>
> $ ./substitute.pl monster '([aeiou])' 'X$1Y'


Now the replacement string needs to be Perl code rather than
stuff to interpolate:

   ./substitute.pl monster '([aeiou])' '"X$1Y"'


> Is there any way to get the substitution as in $text2 without using
> eval?


No. But you can use a prettier eval, as above.

   perldoc -q variable

      How can I expand variables in text strings?


-- 
Tad McClellan
email: perl -le "print scalar reverse qq/moc.noitatibaher\100cmdat/"


------------------------------

Date: Thu, 05 Jun 2008 04:48:49 +0200
From: Gunnar Hjalmarsson <noreply@gunnar.cc>
Subject: Re: RHS of s/LHS/RHS/ with $1, $2, etc. without "eval"?
Message-Id: <6ap2k2F37do7sU1@mid.individual.net>

Ben Bullock wrote:
> The following script
> 
> #! perl -lw
> use strict;
> my ($text, $left, $right) = @ARGV[0..2];
> my $text1 = $text;
> $text1 =~ s/$left/$right/g;
> print $text1;
> my $text2 = $text;
> eval ("\$text2 =~ s/$left/$right/g");
> print $text2;
> 
> prints
> 
> $ ./substitute.pl monster '([aeiou])' 'X$1Y'
> mX$1YnstX$1Yr
> mXoYnstXeYr
> 
> Is there any way to get the substitution as in $text2 without using
> eval?

     $text2 =~ s/$left/ convert($1, $right) /eg;

     sub convert {
         my ($capt, $right) = @_;
         $right =~ s/\$1/$capt/;
         $right;
     }

-- 
Gunnar Hjalmarsson
Email: http://www.gunnar.cc/cgi-bin/contact.pl


------------------------------

Date: Thu, 05 Jun 2008 03:01:21 GMT
From: Michael Carman <mjcarman@mchsi.com>
Subject: Re: RHS of s/LHS/RHS/ with $1, $2, etc. without "eval"?
Message-Id: <4GI1k.140359$TT4.89514@attbi_s22>

Ben Bullock wrote:
> The following script
> 
> #! perl -lw
> use strict;
> my ($text, $left, $right) = @ARGV[0..2];
> my $text1 = $text;
> $text1 =~ s/$left/$right/g;
> print $text1;
> my $text2 = $text;
> eval ("\$text2 =~ s/$left/$right/g");
> print $text2;
> 
> prints
> 
> $ ./substitute.pl monster '([aeiou])' 'X$1Y'
> mX$1YnstX$1Yr
> mXoYnstXeYr
> 
> Is there any way to get the substitution as in $text2 without using
> eval?

If you change $right to '"X$1Y"' (which you could do automatically 
inside the script) you can then do

   $text =~ s/$left/$right/eeg;

to force two-pass interpolation. (Note that this is really just an eval 
in different clothing.) This works for the case you've provided but my 
gut tells me that there's a failure case lurking somewhere. Caveat user.

Also, it should be apparent that executing user-provided code is a 
potential security hole. Depending on where (and by whom) this will run 
you should consider using taint mode and validating that $right is safe 
before using it.

> Also, $& gives the value of what matched $left, but is there any
> variable which gives the post-substitution value, that is the value of
> $right after the $1, $2 substitutions has been performed?

The value of $right is 'X$1Y'. The interpolation of $1 doesn't happen 
until you eval it. It

-mjc


------------------------------

Date: Wed, 4 Jun 2008 15:22:29 -0700 (PDT)
From: Mason.Guy@gmail.com
Subject: Stopping a File::Find on first find
Message-Id: <75e0a558-9293-4061-b5e3-163e121aae28@r66g2000hsg.googlegroups.com>

I've got a script that searches for a file in a dir heirarchy that
contains a lot of files (using find of File::Find).

The problem is, find searches through the entire dir tree to find all
possible matches.  This takes a considerable amount of time.

Is there a way to get find to exit early?

Thanks,
Mason


------------------------------

Date: Wed, 4 Jun 2008 23:41:57 +0100
From: Ben Morrow <ben@morrow.me.uk>
Subject: Re: Stopping a File::Find on first find
Message-Id: <laijh5-oh41.ln1@osiris.mauzo.dyndns.org>


Quoth Mason.Guy@gmail.com:
> I've got a script that searches for a file in a dir heirarchy that
> contains a lot of files (using find of File::Find).
> 
> The problem is, find searches through the entire dir tree to find all
> possible matches.  This takes a considerable amount of time.
> 
> Is there a way to get find to exit early?

The obvious way is to wrap the call to find in eval {}, and call 'die'
from within wanted().

Ben

-- 
I have two words that are going to make all your troubles go away.
"Miniature". "Golf".
                                                         [ben@morrow.me.uk]


------------------------------

Date: Wed, 4 Jun 2008 15:56:14 -0700 (PDT)
From: "jl_post@hotmail.com" <jl_post@hotmail.com>
Subject: Re: Stopping a File::Find on first find
Message-Id: <7557219e-2850-4265-a035-048cafbd829d@y21g2000hsf.googlegroups.com>

On Jun 4, 4:22 pm, Mason....@gmail.com wrote:
>
> I've got a script that searches for a file in a dir heirarchy that
> contains a lot of files (using find of File::Find).
>
> The problem is, find searches through the entire dir tree to find all
> possible matches.  This takes a considerable amount of time.
>
> Is there a way to get find to exit early?


Dear Mason,

   I once had a similar problem in that I wanted to stop File::Find as
soon as it found any file in the directory structure that was modified
within a set amount of time.

   I don't know if my solution is the best solution, but it definitely
worked.

   First, I created a variable to keep track if I had what I wanted:

      my $found = 0;  # initialize to false

Then I put it in the wanted() function (the one that File::Find()
uses) like this:

      sub wanted
      {
         return  if $found;

          # Rest of wanted() logic that
          # ends in something like this:
         if (no_need_to_continue_searching)
         {
            $found = 1;
         }
      }

   This will stop the wanted() function from executing the bulk of its
code with for each of the remaining files.  However, this still
doesn't stop File::Find() from traversing the directory trees.

   To stop File::Find() from traversing the directory trees, I made
use of the "preprocess" option (it's documented in "perldoc
File::Find").  I just created a function like:

      sub preprocessDirEntries
      {
         return $found ? () : @_;
      }

and passed in &preprocessDirEntries as the value of the "preprocess"
option.  Then when File::Find() opens a new directory to traverse, the
preprocessDirEntries() will make it think that it has no file entries
inside it, and so it will not traverse the directory structure any
deeper.

   Using this approach will still make File::Find() traverse through
the rest of the files in the directory you are in when you set $found
to a true value, but it won't search through other directories (even
sub-directories).

   And the early exit I showed you in the first step will be utilized
for any remaining entries in the current directory, which should lead
to a quick exit without too much extra processing.

   So you can use this for your File::Find() statement:

   find( { wanted => \&wanted,
           preprocess => \&preprocessDirEntries },
         @directories_to_search)

   I hope this helps, Mason.  Like I said, I don't know if this is the
best solution, but it's one that worked for me.

   -- Jean-Luc


------------------------------

Date: Wed, 4 Jun 2008 19:38:04 -0500
From: Tad J McClellan <tadmc@seesig.invalid>
Subject: Re: XML::Parser Tree Style
Message-Id: <slrng4edbc.f7u.tadmc@tadmc30.sbcglobal.net>

Ben Bullock <benkasminbullock@gmail.com> wrote:
> On Wed, 04 Jun 2008 02:19:17 -0700, NiallBCarter wrote:

>>  Tad McClellan wrote:
>>>   print "FOUND\n\n", XML::XPath::XMLParser::as_string($node), "\n\n";
>> 
>> All well and good Tad but XML::Path is not installed and I have been
>> told that it will not be installed.


If installed your task is completed in 3 lines of code and 10 minutes
of programmer time.

How many hours will it take you without the module?

Are your sysadmins paid many times more than you are?

If not, then it would seem to be bad business to spend money on
reinventing a perfectly good wheel.

Does your manager want to get promoted someday?

Ask him if he prefers spending 10 minutes or 4 hours to get the same thing...


> You can install it locally in your own account.


Then you are done in 10 minutes without annoying the sysadmins
and managers that balk at performing their job function 
(providing the resources that their users need).


> Note that since Tad McClellan may not even have seen this, to get a better
> response I recommend that you reply to Tad McClellan in a separate
> message as a direct followup to him.


Indeed.

I missed seeing that "followup".


-- 
Tad McClellan
email: perl -le "print scalar reverse qq/moc.noitatibaher\100cmdat/"


------------------------------

Date: 6 Apr 2001 21:33:47 GMT (Last modified)
From: Perl-Users-Request@ruby.oce.orst.edu (Perl-Users-Digest Admin) 
Subject: Digest Administrivia (Last modified: 6 Apr 01)
Message-Id: <null>


Administrivia:

#The Perl-Users Digest is a retransmission of the USENET newsgroup
#comp.lang.perl.misc.  For subscription or unsubscription requests, send
#the single line:
#
#	subscribe perl-users
#or:
#	unsubscribe perl-users
#
#to almanac@ruby.oce.orst.edu.  

NOTE: due to the current flood of worm email banging on ruby, the smtp
server on ruby has been shut off until further notice. 

To submit articles to comp.lang.perl.announce, send your article to
clpa@perl.com.

#To request back copies (available for a week or so), send your request
#to almanac@ruby.oce.orst.edu with the command "send perl-users x.y",
#where x is the volume number and y is the issue number.

#For other requests pertaining to the digest, send mail to
#perl-users-request@ruby.oce.orst.edu. Do not waste your time or mine
#sending perl questions to the -request address, I don't have time to
#answer them even if I did know the answer.


------------------------------
End of Perl-Users Digest V11 Issue 1612
***************************************


home help back first fref pref prev next nref lref last post