diff --git a/.gitignore b/.gitignore index 12f90dc..e56776c 100755 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,8 @@ nytprof* MYMETA.* *.o bin/perl5i -bin/perl5i.c +bin/perl5i.h bin/perl5i.bat .prove *.swp +*.dSYM/ \ No newline at end of file diff --git a/Build.PL b/Build.PL index ec016c4..aececf0 100644 --- a/Build.PL +++ b/Build.PL @@ -102,7 +102,7 @@ my $builder = MyBuild->new( }, PL_files => { - 'bin/perl5i.c.PL' => 'bin/perl5i.c', + 'bin/perl5i.h.PL' => 'bin/perl5i.h', 'bin/perl5i.bat.PL' => 'bin/perl5i.bat', }, diff --git a/MANIFEST b/MANIFEST index 37dd2f1..b9f4d35 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1,7 +1,8 @@ .perlcriticrc .perltidyrc bin/perl5i.bat.PL -bin/perl5i.c.PL +bin/perl5i.c +bin/perl5i.h.PL bin/perl5i.plx Build.PL Changes diff --git a/MANIFEST.SKIP b/MANIFEST.SKIP index fddbb52..b5a7336 100644 --- a/MANIFEST.SKIP +++ b/MANIFEST.SKIP @@ -63,7 +63,7 @@ # Don't ship perl5i ^bin/perl5i$ -^bin/perl5i.c$ +^bin/perl5i.h$ ^bin/perl5i.bat$ # Ignore C object files diff --git a/bin/perl5i.c b/bin/perl5i.c new file mode 100644 index 0000000..59abc46 --- /dev/null +++ b/bin/perl5i.c @@ -0,0 +1,44 @@ +/* + * Meant to mimic the shell command + * exec perl -Mperl5i::latest "$@" + * + * This is a C program so it works in a #! line with minimal overhead. + */ + +#define DEBUG 0 + +#include +#include +#include +#include +#include +#include "perl5i.h" + +char *safe_cat(char *a, char*b) { + char *new = malloc(sizeof(char) * (strlen(a) + strlen(b) + 1)); + + strcpy(new, a); + strcat(new, b); + + return new; +} + +int main (int argc, char* argv[]) { + int i; + + char **exec_args = malloc(sizeof(char*) * (argc + 2)); + int num_exec_args = argc + 1; + + /* Insert -Mperl5i::cmd=... into a copy of argv */ + exec_args[0] = argv[0]; + exec_args[1] = safe_cat("-Mperl5i::cmd=", argv[0]); + for( i = 1; i < argc; i++ ) { + exec_args[i+1] = argv[i]; + } + + exec_args[num_exec_args] = NULL; + + execv(Perl_Path, exec_args ); + + fprintf(stderr, "Executing %s failed: %s\n", Perl_Path, strerror(errno)); +} diff --git a/bin/perl5i.c.PL b/bin/perl5i.c.PL deleted file mode 100644 index ad2bcb0..0000000 --- a/bin/perl5i.c.PL +++ /dev/null @@ -1,115 +0,0 @@ -# Write out the perl5i wrapper C program making sure it uses -# the Perl its built with. - -use strict; -use warnings; -use File::Spec; - -my $file = shift; - -# Its going inside double quotes. -my $perl_path = $^X; -$perl_path =~ s{ ([\\"]) }{\\$1}gx; - -my $tempdir = File::Spec->tmpdir || "/tmp"; - -open my $fh, ">", $file or die $!; -printf $fh <<'END', $0, $perl_path, $tempdir; -/* THIS FILE IS GENERATED BY %s - * Any changes here will be wiped out. Edit it there instead. - */ - -#define DEBUG 0 - -#include -#include -#include -#include - -/* - * Meant to mimic the shell command - * exec perl -Mperl5i::latest "$@" - * - * This is a C program so it works in a #! line. - */ - -int main (int argc, char* argv[]) { - int i; - int j; - const char* perl_cmd = "%s"; - char* perl_args[argc+1]; - char* dash_m = (char *)malloc(sizeof(char) * (strlen(argv[0]) + 20)); - char* program = ""; - int saw_dash_e = 0; - - strcpy(dash_m, "-Mperl5i::cmd="); - strcat(dash_m, argv[0]); - - perl_args[0] = (char *)perl_cmd; - perl_args[1] = dash_m; - - for( i = 1, j = 2; i < argc; i++ ) { - char *dash_e = strchr(argv[i], 'e'); - - /* Its a one liner */ - if( dash_e - && dash_e > argv[i] - && *(dash_e-1) == '-' - && (strchr(argv[i], '-') == argv[i]) - && i+1 < argc - ) - { - saw_dash_e = 1; - - /* Chop out the -e */ - dash_e[0] = '\0'; - - /* If all that's left is a dash, ignore it */ - if( strcmp(argv[i], "-") != 0 ) { - perl_args[j] = argv[i]; - j++; - } - - /* Skip the next argument, its the program */ - i++; - program = argv[i]; - continue; - } - - perl_args[j] = argv[i]; - j++; - } - - /* Turn one liners into real programs to work around - a Devel::Declare bug */ - if( saw_dash_e ) { - char tempfile[] = "%s/perl5i.XXXXXX"; - int fd = mkstemp(tempfile); - if( fd == -1 ) { - perror("Could not open temporary file 'tempfile'"); - exit(1); - } - FILE *fh = fdopen(fd, "w"); - fprintf( fh, "$0 = '-e';\n" ); - fprintf( fh, "#line 1 \"-e\"\n" ); - fprintf( fh, "%%s", program ); - fclose(fh); - - perl_args[j++] = tempfile; - } - - /* Argument array must be terminated by a null */ - perl_args[j] = (char *)NULL; - -#if DEBUG - for( i = 0; i <= j; i++ ) { - printf("perl_args[%%d]: %%s\n", i, perl_args[i]); - } - - if( saw_dash_e ) - printf("program: %%s\n", program); -#endif - - return execv( perl_cmd, perl_args ); -} -END diff --git a/bin/perl5i.h.PL b/bin/perl5i.h.PL new file mode 100644 index 0000000..918068f --- /dev/null +++ b/bin/perl5i.h.PL @@ -0,0 +1,23 @@ +# Write out a header config file for the perl5i C wrapper. + +use strict; +use warnings; +use File::Spec; + +my $file = shift; + +# Its going inside double quotes. +my $perl_path = $^X; +$perl_path =~ s{ ([\\"]) }{\\$1}gx; + +my $tempdir = File::Spec->tmpdir || "/tmp"; + +open my $fh, ">", $file or die $!; +printf $fh <<"END"; +/* THIS FILE IS GENERATED BY $0 + * Any changes here will be wiped out. Edit it there instead. + */ + +const char Perl_Path[] = "$perl_path"; +const char Temp_Template[] = "$tempdir/perl5i.XXXXXXXX"; +END diff --git a/t/command_line_wrapper.t b/t/command_line_wrapper.t index 509cd01..6c22ae0 100755 --- a/t/command_line_wrapper.t +++ b/t/command_line_wrapper.t @@ -28,6 +28,10 @@ like `$perl5icmd -h`, qr/disable all warnings/, 'perl5i -h works as expected'; like capture { system @perl5icmd, "-e", '$^X->say' }, qr/perl5i/, '$^X is perl5i'; +is capture { system @perl5icmd, "-e", 'say @ARGV', 'foo', 'bar' }, "foobar\n", "-e with args"; + +is capture { system @perl5icmd, "-e", 'func foo() { say 42 } foo()' }, "42\n", "-e with Devel::Declare"; + is capture { system @perl5icmd, '-wle', q[print 'Hello'] }, "Hello\n", "compound -e"; is capture { system @perl5icmd, "-Minteger", "-e", q[say 'Hello'] }, "Hello\n",