From: Tim Bunce Date: Wed, 15 Oct 1997 15:55:26 +0000 (+0000) Subject: Maintenance 5.004_04 changes X-Git-Tag: perl-5.005~823^2 X-Git-Url: https://perl5.git.perl.org/perl5.git/commitdiff_plain/50e27ac33704d6fb34d4be7cfb426b2097b27505?hp=2269e8ecc334a5a77bdb915666547431c0171402 Maintenance 5.004_04 changes p4raw-id: //depot/maint-5.004/perl@128 --- diff --git a/Changes b/Changes index 1675e31..7475501 100644 --- a/Changes +++ b/Changes @@ -42,9 +42,836 @@ current addresses (as of March 1997): And the Keepers of the Patch Pumpkin: Charles Bailey + Tim Bunce Andy Dougherty Chip Salzenberg - Tim Bunce + + +---------------- +Version 5.004_04 Maintenance release 4 for 5.004 +---------------- + +"1. Out of clutter, find simplicity. + 2. From discord, find harmony. + 3. In the middle of difficulty lies opportunity." + -- Albert Einstein, three rules of work + + + HEADLINES FOR THIS MAINTENANCE RELEASE + + Fixed gaps in tainting (readdir, readlink, gecos, bit vector ops). + Fixed memory leak in splice(@_). + Fixed debugger core dumps. + IO::Socket now sets autoflush by default. + Several perldoc bugs fixed, now faster and more helpful. + Fixed Win32 handle leak. + Many other improvements to Win32 support. + Many many other bug fixes and enhancements. + + + ------ BUILD PROCESS ------ + + Title: "ExtUtils::Liblist prints diagnostics to STDOUT (vs. STDERR)" + From: Andy Dougherty , jesse@ginger + (Jesse Glick) + Msg-ID: <199708290032.UAA15663@ginger>, + + Files: MANIFEST lib/ExtUtils/Liblist.pm + + Title: "Set LD_RUN_PATH when building suidperl" + From: Chip Salzenberg , Tony Sanders + + Msg-ID: <199708272226.QAA10206@austin.bsdi.com> + Files: Makefile.SH + + Title: "INSTALL version 1.26" + From: Andy Dougherty + Msg-ID: + Files: INSTALL + + Title: "Propagate MAKE=$(MAKE) through perl build" + From: Andy Dougherty + Msg-ID: + Files: Makefile.SH makedepend.SH x2p/Makefile.SH ext/util/make_ext + + Title: "update to installperl for perl5.004_02 to skip CVS dir" + From: Tony Sanders + Msg-ID: <199708272307.RAA13451@austin.bsdi.com> + Files: installperl + + Title: "makedepend loop on HP-UX 10.20" + Msg-ID: <1997Sep20.183731.2297443@cor.newman> + Files: Makefile.SH + + Title: "Tiny Grammaro in INSTALL" + From: koenig@anna.mind.de (Andreas J. Koenig) + Msg-ID: + Files: INSTALL + + Title: "Fix Configured osvers under Linux 1" + From: Andy Dougherty , Hugo van der + Sanden + Msg-ID: <199709241439.PAA17114@crypt.compulink.co.uk>, + + Files: Configure + + Title: "INSTALL-1.28" + From: Andy Dougherty + Msg-ID: + Files: INSTALL + + Title: "makedepend.SH fix for UNICOS" + From: Jarkko Hietaniemi + Msg-ID: <199710132039.XAA21459@alpha.hut.fi> + Files: makedepend.SH + + ------ CORE LANGUAGE ------ + + Title: "Re: "perl -d" dumps core when loading syslog.ph" + From: Jochen Wiedmann , Stephen McCamant + , ilya@math.ohio-state.edu (Ilya + Zakharevich) + Msg-ID: <1997Aug30.034921.2297381@cor.newman.upenn.edu>, + <3407639E.FEBF20BA@neckar-alb.de>, + + Files: pp_ctl.c + + Title: "Allow $obj->$coderef()" + From: Chip Salzenberg + Msg-ID: <199708291649.MAA23276@nielsenmedia.com> + Files: pp_hot.c + + Title: "Localize PV value in save_gp()", "typeglob differences in perl4 and + perl5" + From: Gurusamy Sarathy , Stephen McCamant + + Msg-ID: <199708272348.TAA03139@aatma.engin.umich.edu>, + + Files: scope.c t/op/ref.t + + Title: "Avoid assumption that STRLEN == I32" + From: Chip Salzenberg , Hallvard B Furuseth + + Msg-ID: <199708242310.BAA05497@bombur2.uio.no> + Files: hv.c + + Title: "Fix memory leak in splice(@_)" + From: "Tuomas J. Lukka" , Chip Salzenberg + + Msg-ID: + Files: proto.h av.c global.sym pp.c + + Title: "Fix line number of warnings in while() conditional", "misleading + uninit value warning" + From: Chip Salzenberg , Greg Bacon + + Msg-ID: <199708271607.LAA01403@crp-201.adtran.com> + Files: proto.h op.c perly.c perly.y + + Title: "-t and POSIX::isatty on IO::Handle objects", "Fix C<-t $handle>" + From: Chip Salzenberg , Greg Ward + + Msg-ID: <199708261754.NAA24826@bottom.bic.mni.mcgill.ca> + Files: pp_sys.c + + Title: "Fix output of invalid printf formats" + From: Chip Salzenberg , Hugo van der Sanden + + Msg-ID: <199708241529.QAA02457@crypt.compulink.co.uk> + Files: sv.c t/op/sprintf.t + + Title: "regexec.c regcppartblow declaration missing an arg" + From: Hugo van der Sanden + Msg-ID: <199708290059.BAA05808@crypt.compulink.co.uk> + Files: regexec.c + + Title: "taint readlink, readdir, gecos" + From: Jarkko Hietaniemi + Msg-ID: <199709131651.TAA13471@alpha.hut.fi> + Files: pod/perlfunc.pod pod/perlsec.pod pp_sys.c t/op/taint.t + + Title: "clean up old style package' usage in op.c" + From: Stephen Potter + Msg-ID: <199709151813.NAA14433@psisa.psa.pencom.com> + Files: op.c + + Title: "beautifying usage() code in perl.c" + From: "John L. Allen" <"John L. Allen"> + Msg-ID: + Files: perl.c + + Title: "debugger to fix core dumps, adds $^S" + From: Ilya Zakharevich + Msg-ID: <199709170823.EAA21359@monk.mps.ohio-state.edu> + Files: pod/perlvar.pod perl.h gv.c lib/perl5db.pl mg.c perl.c toke.c + + Title: "downgrade "my $foo masks earlier" from mandatory to "-w"" + From: Gurusamy Sarathy , Stephen Potter + + Msg-ID: <199709091832.NAA14763@psisa.psa.pencom.com>, + <199709102019.QAA09591@aatma.engin.umich.edu> + Files: pod/perldelta.pod pod/perldiag.pod op.c + + Title: "fix overridden glob() problems" + From: Gurusamy Sarathy + Msg-ID: <199709171645.MAA13988@aatma.engin.umich.edu> + Files: MANIFEST pod/perlsub.pod lib/File/DosGlob.pm op.c t/lib/dosglob.t + toke.c + + Title: "Reverse previous "Fix C" patch" + From: Chip Salzenberg , Kenneth Albanowski + , Tom Christiansen + + Msg-ID: <199707050155.VAA27394@rio.atlantic.net>, + <199708172326.RAA19344@jhereg.perl.com>, + + Files: toke.c + + Title: "printf type warning buglets in m3t2" + From: Hallvard B Furuseth + Msg-ID: <199708141017.MAA10225@bombur2.uio.no> + Files: regcomp.c regexec.c scope.c sv.c util.c x2p/util.c + + Title: "Localize PV value in save_gp()", "typeglob differences in perl4 and + perl5" + From: Gurusamy Sarathy , Stephen McCamant + + Msg-ID: <199708272348.TAA03139@aatma.engin.umich.edu>, + + Files: scope.c t/op/ref.t + + Title: "unpack now allows commas but -w warns", "unpack() difference + 5.003->5.004" + From: "John L. Allen" , Chip Salzenberg + , Jarkko Hietaniemi , + Jim Esten , Jim Esten + , timbo (Tim Bunce) + Msg-ID: <199709031632.LAA29584@wepco.com>, + <199709090257.WAA32670@rio.atlantic.net>, + <199709090917.MAA05602@alpha.hut.fi>, + <199709091000.LAA24094@toad.ig.co.uk>, + <341077FE.132F@wdynamic.com>, + + Files: pod/perldiag.pod pp.c + + Title: "5.004_04 trial 1 assorted minor details" + From: Hallvard B Furuseth + Msg-ID: + Files: Porting/pumpkin.pod hv.c op.c sv.c x2p/util.c + + Title: "A couple of 4_04t1 problems" + From: pmarquess@bfsec.bt.co.uk (Paul Marquess) + Msg-ID: <9709210959.AA28772@claudius.bfsec.bt.co.uk> + Files: lib/Cwd.pm perl.c + + Title: "Minor changes to ease port to MVS" + From: Len Johnson , SMTP%"BAHUFF@us.oracle.com" , + SMTP%"pfuntner@vnet.ibm.com" , pvhp@forte.com (Peter + Prymmer) + Msg-ID: <199709162058.NAA00952@mailsun2.us.oracle.com> + Files: unixish.h miniperlmain.c + + Title: "Truer version string and more robust perlbug" + From: "Michael A. Chase" , Hugo van der Sanden + + Msg-ID: <199709201514.QAA21187@crypt.compulink.co.uk>, + <1997Sep22.090701.2297448@cor.newman> + Files: perl.c utils/perlbug.PL + + Title: "Fix locale bug for constant (readonly) strings" + From: Jarkko Hietaniemi + Msg-ID: <199709262125.AAA28292@alpha.hut.fi> + Files: sv.c t/pragma/locale.t + + Title: "Enable truly global glob()" + From: Gurusamy Sarathy + Msg-ID: <199710080000.UAA18972@aatma.engin.umich.edu> + Files: op.c + + Title: "Fix for $0 truncation" + From: Tim Bunce + Msg-ID: <199710081703.SAA02653@toad.ig.co.uk> + Files: mg.c + + Title: "Fix for missing &import leaving stack untidy" + From: Chip Salzenberg + Msg-ID: <199709282252.SAA22915@nielsenmedia.com> + Files: pp_hot.c + + Title: "Larry's proto fix" + From: Chip Salzenberg + Msg-ID: <199709290004.UAA07559@nielsenmedia.com> + Files: op.c t/comp/proto.t + + Title: "Fix bugs with magical arrays and hashes (@ISA)" + From: Chip Salzenberg + Msg-ID: <199709232148.RAA29967@rio.atlantic.net> + Files: perl.h proto.h av.c global.sym gv.c mg.c pp.c pp_hot.c scope.c + t/op/method.t + + Title: "Perl_debug_log stream used for all DEBUG_*(...) macro uses" + From: Nick Ing-Simmons , Tim Bunce + Msg-ID: <199709230820.JAA11945@tiuk.ti.com> + Files: perl.c taint.c util.c + + Title: "Tainting bitwise vector ops" + From: Chip Salzenberg + Msg-ID: <199710061726.NAA16438@rio.atlantic.net> + Files: doop.c t/op/taint.t + + Title: "Enhance $^E on OS/2" + From: Ilya Zakharevich + Msg-ID: <199709232236.SAA04463@monk.mps.ohio-state.edu> + Files: pod/perlvar.pod mg.c os2/Changes + + Title: "option "!#... -- ..." in perl 5.004.03 seems not to work" + From: "John L. Allen" , Urs Thuermann + + Msg-ID: <199709232030.WAA30425@isnogud.escape.de>, + + Files: perl.c + + Title: "syswrite will again write a zero length buffer" + From: Cameron Simpson , Jarkko Hietaniemi , + aml@world.std.com (Andrew M. Langmead) + Msg-ID: <199710042107.AAA28561@alpha.hut.fi>, + <19971007104652-cameron-1-10391@sid.research.canon.com.au> + Files: pp_sys.c + + Title: "make Odd number of elements in hash list warning non-mandatory" + From: Jason Varsoke {81530} + Msg-ID: <199710021651.MAA15690@caesun7.msd.ray.com> + Files: pp.c pp_hot.c + + Title: "Fix defined() bug in m4t3 affecting LWP" + From: chip@atlantic.net@ig.co.uk () + Msg-ID: <199710101822.OAA14249@cyprus.atlantic.net> + Files: pp.c + + Title: "Include $archname in perl -v output" + From: Tim Bunce + Files: perl.c + + Title: "-I flag can easily lead to whitespace in @INC" + From: Kenneth Stephen , Tim Bunce , + pvhp@forte.com (Peter Prymmer) + Msg-ID: <199710130922.KAA07780@toad.ig.co.uk>, + <5040400007001448000002L082*@MHS>, + <9710132015.AA12457@forte.com> + Files: perl.c + + ------ DOCUMENTATION ------ + + Title: "perldiag.pod: gotcha in short pattern/char ops" + From: Jarkko Hietaniemi + Msg-ID: <199709050718.KAA31405@alpha.hut.fi> + Files: pod/perldiag.pod + + Title: "Documenting the perl-thanks address" + From: Tom Phoenix + Msg-ID: + Files: pod/perl.pod + + Title: "Missing section for @_ in perlvar." + From: abigail@fnx.com (Abigail) + Msg-ID: <199708142146.RAA13146@fnx.com> + Files: pod/perlvar.pod + + Title: "Promised information about AvHASH in perguts is not delivered" + From: mjd@plover.com + Files: pod/perlguts.pod + + Title: "perlfunc.doc - $_ aliasing in map, grep, foreach etc" + From: Ted Ashton + Msg-ID: <199708181852.OAA15901@ns.southern.edu> + Files: pod/perlfunc.pod + + Title: "-U Unsafe operations need -w to warn" + From: Tom Phoenix + Msg-ID: + Files: pod/perlrun.pod + + Title: "document the return value of syscall" + From: Hans Mulder + Msg-ID: <1997Sep7.160817.2297395@cor.newman> + Files: pod/perlfunc.pod + + Title: "minor fix for perltrap.pod" + From: abigail@fnx.com (Abigail) + Msg-ID: <199709170500.BAA14805@fnx.com> + Files: pod/perltrap.pod + + Title: "xsubpp: document advanced dynamic typemap usage" + From: "Rujith S. de Silva" + Files: pod/perlxs.pod + + Title: "Improved diagnostic docs for here-documents" + From: Tom Phoenix + Msg-ID: + Files: pod/perldiag.pod + + Title: "[POD patch] do-FILE forces scalar context." + From: Robin Houston + Msg-ID: <199709221553.QAA28409@carryon.oneworld.org> + Files: pod/perlfunc.pod + + Title: "perlop.pop. Behaviour of C vs C." + From: abigail@fnx.com (Abigail) + Msg-ID: <199709220107.VAA27064@fnx.com> + Files: pod/perlop.pod + + Title: "Clarify exec docs in perlfunc.pod" + From: Hugo van der Sanden + Msg-ID: <199710081353.OAA00834@crypt.compulink.co.uk> + Files: pod/perlfunc.pod + + Title: "Documentation patch for perlguts.pod--document tainting routines" + From: Dan Sugalski + Msg-ID: <3.0.3.32.19971007165226.02fd2cd4@osshe.edu> + Files: pod/perlguts.pod + + Title: "Man perlfunc: incorrect split example" + From: Joerg Porath + Msg-ID: <199709240620.IAA30928@pandora.hrz.tu-chemnitz.de> + Files: pod/perlfunc.pod + + Title: "Improve "Use of inherited AUTOLOAD for non-method" disgnostic" + From: rjray@uswest.com (Randy J. Ray) + Msg-ID: <199709231710.LAA08854@tremere.ecte.uswc.uswest.com> + Files: pod/perldiag.pod + + Title: "Document split-with-limit on empty string perl4/perl5 change" + From: "M.J.T. Guy" , Gisle Aas , Hugo + van der Sanden + Msg-ID: <199709221419.PAA03987@crypt.compulink.co.uk>, + + Files: pod/perlfunc.pod pod/perltrap.pod URI/URL/http.pm t/op/split.t + + Title: "Clarify close() docs" + From: Ilya Zakharevich + Msg-ID: <199710081653.MAA20611@monk.mps.ohio-state.edu> + Files: pod/perlfunc.pod + + Title: "perldiag log & sqrt - refer to Math::Complex package" + From: Jarkko Hietaniemi + Msg-ID: <199710042129.AAA20367@alpha.hut.fi> + Files: pod/perldiag.pod + + Title: "perlfunc.pod: sysread, syswrite docs" + From: Jarkko Hietaniemi + Msg-ID: <199710061910.WAA15266@alpha.hut.fi> + Files: pod/perlfunc.pod + + Title: "Document //gc" + From: abigail@fnx.com (Abigail) + Msg-ID: <199709232302.TAA27947@fnx.com> + Files: pod/perlop.pod + + Title: "repeating #! switches" + From: Chip Salzenberg , Robin Barker + + Msg-ID: <199709241736.NAA25855@rio.atlantic.net>, + <24778.9709241501@tempest.cise.npl.co.uk> + Files: pod/perlrun.pod + + Title: "Re: taint documentation bug" + From: Ken Estes , Tom Phoenix + Msg-ID: + Files: pod/perlsec.pod + + ------ LIBRARY AND EXTENSIONS ------ + + Title: "FileHandle.pm fails if Exporter has not been loaded previously" + From: jan.dubois@ibm.net (Jan Dubois) + Msg-ID: <3445e05b.17874041@smtp2.ibm.net> + Files: lib/FileHandle.pm + + Title: "Prefer startperl path over perlpath in MakeMaker" + From: Andreas Klussmann + Msg-ID: <199709162017.WAA05043@troubadix.infosys.heitec.net> + Files: lib/ExtUtils/MM_Unix.pm + + Title: "Sys::Hostname fails under Solaris 2.5 when setuid" + From: Patrick Hayes + Msg-ID: <199708201240.OAA04243@goblin.renault.fr> + Files: lib/Sys/Hostname.pm + + Title: "Cwd::getcwd cannot handle path contains '0' element" + From: Hironori Ikura , Hironori Ikura + , Stephen Zander + Msg-ID: <19970830060142J.hikura@matsu.tcc.co.jp>, + + Files: lib/Cwd.pm + + Title: "Getopt::Long 2.11" + From: JVromans@squirrel.nl (Johan Vromans) + Msg-ID: + Files: lib/Getopt/Long.pm + + Title: "IO::Socket autoflush by default, assume tcp and PeerAddr" + From: "M.J.T. Guy" , Andy Dougherty + , Gisle Aas + + Msg-ID: , + , + + Files: ext/IO/lib/IO/Socket.pm + + Title: "Syslog.pm and missing _PATH_LOG" + From: Ulrich Pfeifer + Msg-ID: + Files: lib/Sys/Syslog.pm + + Title: "Undocumented: $Test::Harness::switches" + From: Achim Bohnet + Msg-ID: <9708272110.AA26904@o09.xray.mpe.mpg.de> + Files: lib/Test/Harness.pm + + Title: "Patches for lib/Math/Complex.pm and t/lib/complex.t" + From: Jarkko Hietaniemi + Msg-ID: <199709102009.WAA27428@anna.in-berlin.de> + Files: lib/Math/Complex.pm t/lib/complex.t + + Title: "Win32: Install.pm not correctly comparing binary files." + From: Jeff Urlwin + Msg-ID: <01BCBFAA.E325C4A0.jurlwin@access.digex.net> + Files: lib/ExtUtils/Install.pm + + Title: "Document that File::Find doesn't follow symlinks" + From: Greg Ward + Msg-ID: <199708191853.OAA07111@bottom.bic.mni.mcgill.ca> + Files: lib/File/Find.pm + + Title: "fix subroutines called in a void context in perl5db.pl" + From: "M.J.T. Guy" + Msg-ID: + Files: lib/perl5db.pl + + Title: "xsubpp fix to allow #ifdef's around entire XSubs" + From: John Tobey + Msg-ID: <199709070034.AAA16457@remote119> + Files: lib/ExtUtils/xsubpp + + Title: "Banishing eval from getopt.pl and Getopt/Std.pm" + From: "John L. Allen" + Msg-ID: + Files: lib/getopt.pl lib/Getopt/Std.pm + + Title: "further complex number patches" + From: Jarkko Hietaniemi , d-lewart@uiuc.edu (Daniel S. Lewart) + Msg-ID: <199709221009.FAA21216@staff2.cso.uiuc.edu>, + <199709221216.PAA15130@alpha.hut.fi> + Files: lib/Math/Complex.pm t/lib/complex.t + + Title: "Trap Time::Local infinite loop" + From: Hugo van der Sanden + Msg-ID: <199710030030.BAA17372@crypt.compulink.co.uk> + Files: lib/Time/Local.pm + + Title: "Cosmetic Test::Harness patch" + From: Ilya Zakharevich + Msg-ID: <199710032226.SAA15354@monk.mps.ohio-state.edu> + Files: lib/Test/Harness.pm + + Title: "ExtUtil::Install sub my_cmp needs to binmode its files" + From: Gurusamy Sarathy , Stephen Potter + + Msg-ID: <199710010617.BAA02037@psisa.psa.pencom.com>, + <199710011819.OAA03288@aatma.engin.umich.edu> + Files: lib/ExtUtils/Install.pm + + Title: "Enable make test "TEST_FILES=t/*.t.were_failing"" + From: Ilya Zakharevich + Msg-ID: <199710032231.SAA15364@monk.mps.ohio-state.edu> + Files: lib/ExtUtils/MM_Unix.pm + + Title: "Fix for autouse.pm" + From: Ilya Zakharevich + Msg-ID: <199710071734.NAA19462@monk.mps.ohio-state.edu> + Files: lib/autouse.pm + + Title: "Math::Complex fixes - fixes problems on m68-linux" + From: Jarkko Hietaniemi + Msg-ID: <199709301422.HAA24368@koah.research.nokia.com> + Files: lib/Math/Complex.pm + + Title: "Updated CPAN.pm for 5.004_04" + From: koenig@anna.mind.de (Andreas J. Koenig) + Msg-ID: + Files: lib/CPAN.pm lib/CPAN/FirstTime.pm + + Title: "debugger bug with 'c subname'" + From: Ilya Zakharevich + Msg-ID: <199709232331.TAA04546@monk.mps.ohio-state.edu> + Files: lib/perl5db.pl + + Title: "Fix atan2 & restrict $t to (-pi,pi] instead of to [-pi,pi]" + From: Daniel S. Lewart, Jarkko Hietaniemi + + Msg-ID: <199710010939.CAA00964@koah.research.nokia.com> + Files: lib/Math/Complex.pm + + Title: "Cwd::fastcwd needs changes to work with tainting" + From: Hugo van der Sanden , Ulrich Pfeifer + , Tim Bunce + Msg-ID: + Files: lib/Cwd.pm + + Title: "use autouse: requires prototype now" + From: user@agate.berkeley.edu + Msg-ID: <9709220450.AA0380@tuzik.HIP.Berkeley.EDU> + Files: lib/autouse.pm + + Title: ""use base qw(Foo Bar);" to set @ISA at compile time" + From: Gisle Aas , Graham Barr , Graham Barr + , Tim Bunce , + jan.dubois@ibm.net (Jan Dubois), larry@wall.org (Larry + Wall) + Msg-ID: <199710022151.WAA21250@toad.ig.co.uk>, + <199710031613.JAA11286@wall.org>, + <199710040829.KAA16739@furu.g.aas.no>, + <3434E4C6.AE24135E@ti.com>, <343C2278.7DC1ADC6@pobox.com>, + <343ec306.50394803@smtp-gw01.ny.us.ibm.net> + Files: lib/base.pm + + Title: "Further Math/Complex.pm enhancements" + From: Jarkko Hietaniemi + Msg-ID: <199710132055.XAA02086@alpha.hut.fi> + Files: lib/Math/Complex.pm t/lib/complex.t + + Title: "Further Math::Complex fixes" + From: Jarkko Hietaniemi + Msg-ID: <199710120933.MAA01165@alpha.hut.fi> + Files: lib/Math/Complex.pm + + ------ OTHER CHANGES ------ + + Title: "POD patches w.r.t. $^S" + From: Ilya Zakharevich + Msg-ID: <199710030001.UAA14241@monk.mps.ohio-state.edu> + Files: ../pod/perlfunc.pod ../pod/perlvar.pod + + Title: "libperl.sl on HP-UX 10.20" + From: "Darren/Torin/Who Ever..." , Hugo van der Sanden + + Msg-ID: <199709250003.BAA18085@crypt.compulink.co.uk>, + <873emkbpit.fsf@perv.daft.com> + Files: + + Title: "myconfig / perl -V: remove randbits and add prototype" + From: Tim Bunce + Msg-ID: <199709290857.JAA07706@toad.ig.co.uk> + Files: myconfig + + Title: "Emacs CPerl update for 5.004_04" + From: Ilya Zakharevich + Msg-ID: <199710140835.EAA26825@monk.mps.ohio-state.edu> + Files: emacs/cperl-mode.el + + Title: "Enhance perly.fixer to help porters." + From: Tim Bunce + Files: perly.fixer + + ------ PORTABILITY - WIN32 ------ + + Title: "Fix win32/Makefile for perl95" + From: Gurusamy Sarathy + Files: win32/Makefile win32/makefile.mk + + Title: "Win32 archnames" + From: Bill Middleton , Gurusamy Sarathy + , Peter Prymmer , Tim + Bunce + Msg-ID: <199709111929.PAA22488@aatma.engin.umich.edu>, + <341719E4.4923@forte.com>, + + Files: win32/config_H.bc win32/config_H.vc + + Title: "pl2bat.bat -> pl2bat.pl change in win32/pod.mak" + From: jan.dubois@ibm.net (Jan Dubois) + Msg-ID: <3411ee6f.9143607@smtp-gw01.ny.us.ibm.net> + Files: win32/pod.mak + + Title: "Add test-notty target to Win32 Makefile" + From: jan.dubois@ibm.net (Jan Dubois) + Msg-ID: <343f5106.12461608@smtp2.ibm.net> + Files: win32/Makefile + + Title: "Bug in Win32::GetShortPathName" + From: Gurusamy Sarathy + Msg-ID: <199710092229.SAA21556@aatma.engin.umich.edu> + Files: win32/win32.c + + Title: "Fix NT handles leak." + From: Gurusamy Sarathy + Msg-ID: <199710111319.JAA10918@aatma.engin.umich.edu> + Files: win32/win32io.c win32/win32sck.c + + Title: "fix socket init duality on win32" + From: Gurusamy Sarathy + Msg-ID: <199710111523.LAA12407@aatma.engin.umich.edu> + Files: win32/win32sck.c + + ------ PORTABILITY - GENERAL ------ + + Title: "Tweak to hints/machten.sh: stop t/lib/complex.t from failing" + From: Dominic Dunlop + Msg-ID: + Files: hints/machten.sh + + Title: "Irix 6.2 build problem - so_locations" + From: "Billinghurst, David" + Msg-ID: + Files: hints/irix_6.sh + + Title: "Porting/pumpkin.pod version 1.13" + From: Andy Dougherty + Msg-ID: + Files: Porting/pumpkin.pod + + Title: "lib/timelocal.t fails test 1 for VMS 7.1" + From: Dan Sugalski + Msg-ID: <3.0.3.32.19970908112449.0087bc90@stargate.lbcc.cc.or.us> + Files: vms/vmsish.h vms/vms.c + + Title: "Patches to updated README.VMS for Perl 5.004_04" + From: Dan Sugalski + Msg-ID: <3.0.3.32.19970918100648.008b1c60@stargate.lbcc.cc.or.us> + Files: README.vms + + Title: "Fix perl build on Digital UNIX after JDK installs libnet.so" + From: Spider Boardman + Msg-ID: <199709191826.OAA18040@Orb.Nashua.NH.US> + Files: hints/dec_osf.sh + + Title: "Updated README.VMS for Perl 5.004_04" + From: Dan Sugalski + Msg-ID: <3.0.3.32.19970912091524.008a3620@stargate.lbcc.cc.or.us> + Files: README.vms + + Title: "Dynixptx hints" + From: bruce@aps.org ("Bruce P. Schuck") + Msg-ID: + Files: hints/dynixptx.sh + + Title: "Minor OS/2 patch for 4_03" + From: Ilya Zakharevich + Msg-ID: <199710032224.SAA15345@monk.mps.ohio-state.edu> + Files: os2/os2.c + + Title: "OS2::REXX improvements" + From: Ilya Zakharevich + Msg-ID: <199709272214.SAA08638@monk.mps.ohio-state.edu> + Files: os2/Changes os2/OS2/REXX/Makefile.PL os2/OS2/REXX/REXX.pm + + Title: "hints/qnx.sh update" + From: Norton Allen + Msg-ID: <199709261508.LAA07889@dolores.harvard.edu> + Files: hints/qnx.sh + + Title: "New hints file for IBM OS/390 OpenEdition (MVS)" + From: pvhp@forte.com (Peter Prymmer) + Msg-ID: <9709240106.AA26484@forte.com> + Files: hints/os390.sh + + Title: "OS/2 Hints" + From: Ilya Zakharevich + Msg-ID: <199710130631.CAA25426@monk.mps.ohio-state.edu> + Files: hints/os2.sh + + ------ TESTS ------ + + Title: "op/glob.t test failure under Win32 with CVS" + From: Warren Jones + Msg-ID: <97Aug26.091048pdt.35761-1@gateway.fluke.com> + Files: t/op/glob.t + + Title: "tests fail if localhost/loopback address not defined" + From: David McLean >, David McLean + + Msg-ID: <34048947.2944@icc.gsfc.nasa.gov> + Files: t/lib/io_sock.t t/lib/io_udp.t + + Title: "Improve pragma/locale test 102 - and don't fail, just warn" + From: Jarkko Hietaniemi + Files: t/pragma/locale.t + + Title: "Invalid test output in t/op/taint.t in trial 1" + From: Dan Sugalski + Msg-ID: <3.0.3.32.19970919160918.00857a50@stargate.lbcc.cc.or.us> + Files: t/op/taint.t + + Title: "Identify t/*/*.t test failing because of file permissions" + From: koenig@anna.mind.de (Andreas J. Koenig) + Msg-ID: + Files: t/TEST + + Title: "fix poor t/op/runlevel.t test" + From: Gurusamy Sarathy , Hugo van der Sanden + , Norton Allen + + Msg-ID: <199709261458.KAA28611@dolores.harvard.edu> + Files: t/op/runlevel.t + + ------ UTILITIES ------ + + Title: "Missing 'require' in auto-generated .pm by h2xs" + From: davidk@tor.securecomputing.com (David Kerry) + Msg-ID: <97Aug27.131618edt.11650@janus.tor.securecomputing.com> + Files: utils/h2xs.PL + + Title: "Perldoc tiny patch to avoid $0" + From: Ilya Zakharevich + Msg-ID: <199709122141.RAA16846@monk.mps.ohio-state.edu> + Files: utils/perldoc.PL + + Title: "h2ph broken in 5.004_02" + From: David Mazieres , + kstar@www.chapin.edu (Kurt D. Starsinic) + Msg-ID: <199708201454.KAA05122@reeducation-labor.lcs.mit.edu>, + <199708201700.KAA02621@www.chapin.edu> + Files: utils/h2ph.PL + + Title: "add key_t caddr_t to h2ph", "eg/sysvipc/ipcsem bug", "update + hints/bsdos.sh" + From: Tony Sanders + Msg-ID: <199708272301.RAA12803@austin.bsdi.com> + Files: eg/sysvipc/ipcsem utils/h2ph.PL + + Title: "perldoc search ., lib and blib/* if -f 'Makefile.PL'" + From: Tim Bunce + Msg-ID: <199708251732.KAA19299@gadget.cscaper.com> + Files: utils/perldoc.PL + + Title: "5.004m4t1: perlbug: NIS domainname gets into wrong places" + From: koenig@anna.mind.de (Andreas J. Koenig) + Msg-ID: + Files: utils/perlbug.PL + + Title: "add better local patch info to perlbug", "perlbug checks perl + build/run version changes" + From: Tim.Bunce@ig.co.uk + Files: utils/perlbug.PL + + Title: "perldoc - suggest modules if requested module not found" + From: Anthony David + Msg-ID: <3439CD83.6969@netinfo.com.au> + Files: utils/perldoc.PL + + Title: "perldoc mail::foo tries to read binary /usr/ucb/mail" + From: "Joseph Moof-in' Hall" , Tim Bunce + Msg-ID: <199710082014.NAA00808@gadget.cscaper.com> + Files: utils/perldoc.PL + + Title: "perldoc -f setpwent (for example) returns no descriptive text" + From: Tim Bunce + Files: utils/perldoc.PL + + Title: "perldoc diffs: don't search auto - much faster" + From: "Joseph N. Hall" + Msg-ID: + Files: utils/perldoc.PL + ---------------- diff --git a/Configure b/Configure index 13f37ef..eb7dd8a 100755 --- a/Configure +++ b/Configure @@ -1764,7 +1764,6 @@ EOM ;; linux) osname=linux case "$3" in - 1*) osvers=1 ;; *) osvers="$3" ;; esac ;; diff --git a/INSTALL b/INSTALL index ffb755a..488a1ce 100644 --- a/INSTALL +++ b/INSTALL @@ -99,8 +99,11 @@ and Configure will use the defaults from then on. After it runs, Configure will perform variable substitution on all the *.SH files and offer to run make depend. -Configure supports a number of useful options. Run B -to get a listing. To compile with gcc, for example, you can run +Configure supports a number of useful options. Run B to +get a listing. See the Porting/Glossary file for a complete list of +Configure variables you can set and their definitions. + +To compile with gcc, for example, you should run sh Configure -Dcc=gcc @@ -325,12 +328,14 @@ and the following directories for manual pages: (Actually, Configure recognizes the SVR3-style /usr/local/man/l_man/man1 directories, if present, and uses those -instead.) The module man pages are stuck in that strange spot so that +instead.) + +The module man pages are stuck in that strange spot so that they don't collide with other man pages stored in /usr/local/man/man3, and so that Perl's man pages don't hide system man pages. On some systems, B would end up calling up Perl's less.pm module man -page, rather than the less program. (This location may change in a -future release of perl.) +page, rather than the less program. (This default location will likely +change to /usr/local/man/man3 in a future release of perl.) Note: Many users prefer to store the module man pages in /usr/local/man/man3. You can do this from the command line with @@ -423,6 +428,9 @@ installed on multiple systems. Here's one way to do that: make test make install cd /tmp/perl5 + # Edit lib///Config.pm to change all the + # install* variables back to reflect where everything will + # really be installed. tar cvf ../perl5-archive.tar . # Then, on each machine where you want to install perl, cd /usr/local # Or wherever you specified as $prefix @@ -459,14 +467,17 @@ compatibility, answer "y". On the other hand, if you are embedding perl into another application and want the maximum namespace protection, then you probably ought to -answer "n" when Configure asks if you want binary compatibility. +answer "n" when Configure asks if you want binary compatibility, or +disable it from the Configure command line with + + sh Configure -Ud_bincompat3 The default answer of "y" to maintain binary compatibility is probably appropriate for almost everyone. -In a related issue, old extensions may possibly be affected by the changes -in the Perl language in the current release. Please see pod/perldelta for -a description of what's changed. +In a related issue, old extensions may possibly be affected by the +changes in the Perl language in the current release. Please see +pod/perldelta.pod for a description of what's changed. =head2 Selecting File IO mechanisms @@ -626,7 +637,7 @@ to point to the perl build directory. The only reliable answer is that you should specify a different directory for the architecture-dependent library for your -DDEBUGGING -version of perl. You can do this with by changing all the *archlib* +version of perl. You can do this by changing all the *archlib* variables in config.sh, namely archlib, archlib_exp, and installarchlib, to point to your new architecture-dependent library. @@ -1159,9 +1170,9 @@ should run plain 'make' before 'make test' otherwise you won't have a complete build). If 'make test' doesn't say "All tests successful" then something went wrong. See the file t/README in the t subdirectory. -If you want to run make test in the background you should Note that you can't run the tests in background if this disables -opening of /dev/tty. +opening of /dev/tty. You can use 'make test-notty' in that case but +a few tty tests will be skipped. If make test bombs out, just cd to the t directory and run ./TEST by hand to see if it makes any difference. If individual tests @@ -1174,10 +1185,10 @@ individual subtests is to cd to the t directory and run ./perl harness -(this assumes that most tests succeed, since harness uses +(this assumes that most basic tests succeed, since harness uses complicated constructs). -You can also read the individual tests to see if there are any helpful +You should also read the individual tests to see if there are any helpful comments that apply to your system. Note: One possible reason for errors is that some external programs @@ -1343,13 +1354,13 @@ to hand-edit some of the converted files to get them to parse correctly. For example, h2ph breaks spectacularly on type casting and certain structures. -=head installhtml --help +=head1 installhtml --help Some sites may wish to make perl documentation available in HTML format. The installhtml utility can be used to convert pod -documentation into linked HTML files and install install them. +documentation into linked HTML files and install them. -The following command-line is an example of the one we use to convert +The following command-line is an example of one used to convert perl documentation: ./installhtml \ @@ -1369,6 +1380,9 @@ see warnings like "no title", "unexpected directive" and "cannot resolve" as the files are processed. We are aware of these problems (and would welcome patches for them). +You may find it helpful to run installhtml twice. That should reduce +the number of "cannot resolve" warnings. + =head1 cd pod && make tex && (process the latex files) Some sites may also wish to make the documentation in the pod/ directory @@ -1417,10 +1431,14 @@ generate the documentation. =head1 AUTHOR -Andy Dougherty doughera@lafcol.lafayette.edu , borrowing very heavily -from the original README by Larry Wall, and also with lots of helpful -feedback from the perl5-porters@perl.org folks. +Original author: Andy Dougherty doughera@lafcol.lafayette.edu , +borrowing very heavily from the original README by Larry Wall, +with lots of helpful feedback and additions from the +perl5-porters@perl.org folks. + +If you have problems or questions, please see L<"Reporting Problems"> +above. =head1 LAST MODIFIED -$Id: INSTALL,v 1.22 1997/08/01 15:39:14 doughera Released $ +$Id: INSTALL,v 1.28 1997/10/10 16:50:59 doughera Released $ diff --git a/MANIFEST b/MANIFEST index 1977114..26a5409 100644 --- a/MANIFEST +++ b/MANIFEST @@ -206,7 +206,6 @@ ext/SDBM_File/typemap SDBM extension interface types ext/Socket/Makefile.PL Socket extension makefile writer ext/Socket/Socket.pm Socket extension Perl module ext/Socket/Socket.xs Socket extension external subroutines -ext/util/extliblist Used by extension Makefile.PL to make lib lists ext/util/make_ext Used by Makefile to execute extension Makefiles ext/util/mkbootstrap Turns ext/*/*_BS into bootstrap info form.h Public declarations for the above @@ -275,6 +274,7 @@ hints/next_3_0.sh Hints for named architecture hints/next_4.sh Hints for named architecture hints/opus.sh Hints for named architecture hints/os2.sh Hints for named architecture +hints/os390.sh Hints for named architecture hints/powerux.sh Hints for named architecture hints/qnx.sh Hints for named architecture hints/sco.sh Hints for named architecture @@ -400,6 +400,7 @@ lib/User/pwent.pm By-name interface to Perl's builtin getpw* lib/abbrev.pl An abbreviation table builder lib/assert.pl assertion and panic with stack trace lib/autouse.pm Load and call a function only when it's used +lib/base.pm Establish IS-A relationship at compile time lib/bigfloat.pl An arbitrary precision floating point package lib/bigint.pl An arbitrary precision integer arithmetic package lib/bigrat.pl An arbitrary precision rational arithmetic package @@ -652,6 +653,7 @@ t/lib/db-btree.t See if DB_File works t/lib/db-hash.t See if DB_File works t/lib/db-recno.t See if DB_File works t/lib/dirhand.t See if DirHandle works +t/lib/dosglob.t See if File::DosGlob works t/lib/english.t See if English works t/lib/env.t See if Env works t/lib/filecache.t See if FileCache works diff --git a/Makefile.SH b/Makefile.SH index 86fd6ed..f2a4a9f 100644 --- a/Makefile.SH +++ b/Makefile.SH @@ -52,6 +52,9 @@ true) aixinstdir=`pwd | sed 's/\/UU$//'` linklibperl="-L $archlibexp/CORE -L $aixinstdir -lperl" ;; + hpux10*) + linklibperl="-L `pwd | sed 's/\/UU$//'` -Wl,+b$archlibexp/CORE -lperl" + ;; esac ;; *) pldlflags='' @@ -303,13 +306,13 @@ perl: $& perlmain$(OBJ_EXT) $(LIBPERL) $(DYNALOADER) $(static_ext) ext.libs $(SHRPENV) $(CC) $(LARGE) $(CLDFLAGS) $(CCDLFLAGS) -o perl perlmain$(OBJ_EXT) $(DYNALOADER) $(static_ext) $(LLIBPERL) `cat ext.libs` $(libs) pureperl: $& perlmain$(OBJ_EXT) $(LIBPERL) $(DYNALOADER) $(static_ext) ext.libs - purify $(CC) $(LARGE) $(CLDFLAGS) $(CCDLFLAGS) -o pureperl perlmain$(OBJ_EXT) $(DYNALOADER) $(static_ext) $(LLIBPERL) `cat ext.libs` $(libs) + $(SHRPENV) purify $(CC) $(LARGE) $(CLDFLAGS) $(CCDLFLAGS) -o pureperl perlmain$(OBJ_EXT) $(DYNALOADER) $(static_ext) $(LLIBPERL) `cat ext.libs` $(libs) purecovperl: $& perlmain$(OBJ_EXT) $(LIBPERL) $(DYNALOADER) $(static_ext) ext.libs - purecov $(CC) $(LARGE) $(CLDFLAGS) $(CCDLFLAGS) -o purecovperl perlmain$(OBJ_EXT) $(DYNALOADER) $(static_ext) $(LLIBPERL) `cat ext.libs` $(libs) + $(SHRPENV) purecov $(CC) $(LARGE) $(CLDFLAGS) $(CCDLFLAGS) -o purecovperl perlmain$(OBJ_EXT) $(DYNALOADER) $(static_ext) $(LLIBPERL) `cat ext.libs` $(libs) quantperl: $& perlmain$(OBJ_EXT) $(LIBPERL) $(DYNALOADER) $(static_ext) ext.libs - quantify $(CC) $(LARGE) $(CLDFLAGS) $(CCDLFLAGS) -o quantperl perlmain$(OBJ_EXT) $(DYNALOADER) $(static_ext) $(LLIBPERL) `cat ext.libs` $(libs) + $(SHRPENV) quantify $(CC) $(LARGE) $(CLDFLAGS) $(CCDLFLAGS) -o quantperl perlmain$(OBJ_EXT) $(DYNALOADER) $(static_ext) $(LLIBPERL) `cat ext.libs` $(libs) # This version, if specified in Configure, does ONLY those scripts which need # set-id emulation. Suidperl must be setuid root. It contains the "taint" @@ -317,7 +320,7 @@ quantperl: $& perlmain$(OBJ_EXT) $(LIBPERL) $(DYNALOADER) $(static_ext) ext.libs # has been invoked correctly. suidperl: $& sperl$(OBJ_EXT) perlmain$(OBJ_EXT) $(LIBPERL) $(DYNALOADER) $(static_ext) ext.libs - $(CC) $(LARGE) $(CLDFLAGS) $(CCDLFLAGS) -o suidperl perlmain$(OBJ_EXT) sperl$(OBJ_EXT) $(DYNALOADER) $(static_ext) $(LLIBPERL) `cat ext.libs` $(libs) + $(SHRPENV) $(CC) $(LARGE) $(CLDFLAGS) $(CCDLFLAGS) -o suidperl perlmain$(OBJ_EXT) sperl$(OBJ_EXT) $(DYNALOADER) $(static_ext) $(LLIBPERL) `cat ext.libs` $(libs) !NO!SUBS! @@ -341,6 +344,8 @@ preplibrary: miniperl lib/Config.pm $(plextract) autosplit_lib_modules(@ARGV)' lib/*.pm lib/*/*.pm # Take care to avoid modifying lib/Config.pm without reason +# (If trying to create a new port and having problems with the configpm script, +# try 'make minitest' and/or commenting out the tests at the end of configpm.) lib/Config.pm: config.sh miniperl configpm ./miniperl configpm tmp sh mv-if-diff tmp lib/Config.pm @@ -382,12 +387,14 @@ install.html: all installhtml run_byacc: FORCE @ echo 'Expect' 113 shift/reduce and 1 reduce/reduce conflict $(BYACC) -d perly.y + chmod 664 perly.c sh $(shellflags) ./perly.fixer y.tab.c perly.c sed -e 's/fprintf *( *stderr *,/PerlIO_printf(Perl_debug_log,/g' \ -e 's/y\.tab/perly/g' perly.c >perly.tmp && mv perly.tmp perly.c echo 'extern YYSTYPE yylval;' >>y.tab.h cmp -s y.tab.h perly.h && rm -f y.tab.h || mv y.tab.h perly.h - - perl vms/vms_yfix.pl perly.c perly.h vms/perly_c.vms vms/perly_h.vms + chmod 664 vms/perly_c.vms vms/perly_h.vms + perl vms/vms_yfix.pl perly.c perly.h vms/perly_c.vms vms/perly_h.vms # We don't want to regenerate perly.c and perly.h, but they might # appear out-of-date after a patch is applied or a new distribution is @@ -422,13 +429,13 @@ regen_headers: FORCE # DynaLoader may be needed for extensions that use Makefile.PL. $(DYNALOADER): miniperl preplibrary FORCE - @sh ext/util/make_ext static $@ LIBPERL_A=$(LIBPERL) + @sh ext/util/make_ext static $@ MAKE=$(MAKE) LIBPERL_A=$(LIBPERL) d_dummy $(dynamic_ext): miniperl preplibrary $(DYNALOADER) FORCE - @sh ext/util/make_ext dynamic $@ LIBPERL_A=$(LIBPERL) + @sh ext/util/make_ext dynamic $@ MAKE=$(MAKE) LIBPERL_A=$(LIBPERL) s_dummy $(static_ext): miniperl preplibrary $(DYNALOADER) FORCE - @sh ext/util/make_ext static $@ LIBPERL_A=$(LIBPERL) + @sh ext/util/make_ext static $@ MAKE=$(MAKE) LIBPERL_A=$(LIBPERL) clean: _tidy _mopup @@ -453,7 +460,7 @@ _tidy: -cd utils; $(MAKE) clean -cd x2p; $(MAKE) clean -@for x in $(DYNALOADER) $(dynamic_ext) $(static_ext) ; do \ - sh ext/util/make_ext clean $$x ; \ + sh ext/util/make_ext clean $$x MAKE=$(MAKE) ; \ done # Do not 'make _cleaner' directly. @@ -463,7 +470,7 @@ _cleaner: -cd utils; $(MAKE) realclean -cd x2p; $(MAKE) realclean -@for x in $(DYNALOADER) $(dynamic_ext) $(static_ext) ; do \ - sh ext/util/make_ext realclean $$x ; \ + sh ext/util/make_ext realclean $$x MAKE=$(MAKE) ; \ done rm -f *.orig */*.orig *~ */*~ core t/core t/c t/perl rm -rf $(addedbyconf) @@ -482,11 +489,13 @@ _cleaner: lint: perly.c $(c) lint $(lintflags) $(defs) perly.c $(c) > perl.fuzz -# Need to unset during recursion to go out of loop +# Need to unset during recursion to go out of loop. +# The README below ensures that the dependency list is never empty and +# that when MAKEDEPEND is empty $(FIRSTMAKEFILE) doesn't need rebuilding. MAKEDEPEND = Makefile makedepend -$(FIRSTMAKEFILE): $(MAKEDEPEND) +$(FIRSTMAKEFILE): README $(MAKEDEPEND) $(MAKE) depend MAKEDEPEND= config.h: config_h.SH config.sh @@ -497,7 +506,7 @@ perl.exp: perl_exp.SH config.sh # When done, touch perlmain.c so that it doesn't get remade each time. depend: makedepend - sh ./makedepend + sh ./makedepend MAKE=$(MAKE) - test -s perlmain.c && touch perlmain.c cd x2p; $(MAKE) depend @@ -523,8 +532,10 @@ minitest: miniperl - cd t && (rm -f perl$(EXE_EXT); $(LNS) ../miniperl$(EXE_EXT) perl$(EXE_EXT)) \ && ./perl TEST base/*.t comp/*.t cmd/*.t io/*.t op/*.t pragma/*.t 'BUILD PROCESS', @@ -57,7 +71,7 @@ my %cat_title = ( 'DOC' => 'DOCUMENTATION', 'LIB' => 'LIBRARY AND EXTENSIONS', 'PORT1' => 'PORTABILITY - WIN32', - 'PORT2' => 'PORTABILITY - OTHER', + 'PORT2' => 'PORTABILITY - GENERAL', 'TEST' => 'TESTS', 'UTIL' => 'UTILITIES', 'OTHER' => 'OTHER CHANGES', @@ -84,6 +98,8 @@ my %ls; # Index: embed.h my($in, $prevline, $prevtype, $ls); +my(@removed, @added); +my $prologue = 1; # assume prologue till patch or /^exit\b/ seen foreach my $argv (@ARGV) { $in = $argv; @@ -96,16 +112,24 @@ foreach my $argv (@ARGV) { my $type; while () { unless (/^([-+*]{3}) / || /^(Index):/) { - # not an interesting patch line but possibly meta-information + # not an interesting patch line + # but possibly meta-information or prologue + if ($prologue) { + push @added, $1 if /^touch\s+(\S+)/; + push @removed, $1 if /^rm\s+(?:-f)?\s*(\S+)/; + $prologue = 0 if /^exit\b/; + } next unless $::opt_m; - $ls->{From}{$1}=1 if /^From:\s+(.*\S)/i; - $ls->{Title}{$1}=1 if /^Subject:\s+(?:Re: )?(.*\S)/i; - $ls->{'Msg-ID'}{$1}=1 if /^Message-Id:\s+(.*\S)/i; - $ls->{Date}{$1}=1 if /^Date:\s+(.*\S)/i; + $ls->{From}{$1}=1,next if /^From:\s+(.*\S)/i; + $ls->{Title}{$1}=1,next if /^Subject:\s+(?:Re: )?(.*\S)/i; + $ls->{'Msg-ID'}{$1}=1,next if /^Message-Id:\s+(.*\S)/i; + $ls->{Date}{$1}=1,next if /^Date:\s+(.*\S)/i; + $ls->{$1}{$2}=1,next if /^([-\w]+):\s+(.*\S)/; next; } $type = $1; next if /^--- [0-9,]+ ----$/ || /^\*\*\* [0-9,]+ \*\*\*\*$/; + $prologue = 0; print "Last: $prevline","This: ${_}Got: $1\n\n" if $::opt_d; @@ -113,12 +137,12 @@ foreach my $argv (@ARGV) { # Patch copes with this, so must we. It's also handy for # documenting manual changes by simply adding Index: lines # to the file which describes the problem bing fixed. - add_file($ls, $1), next if /^Index:\s+(.*)/; + add_file($ls, $1), next if /^Index:\s+(\S+)/; if ( ($type eq '---' and $prevtype eq '***') # Style 1 or ($type eq '+++' and $prevtype eq '---') # Style 2 ) { - if (/^[-+*]{3} (\S+)\s+.*\d\d:\d\d:\d\d/) { # double check + if (/^[-+*]{3} (\S+)\s*(.*?\d\d:\d\d:\d\d)?/) { # double check add_file($ls, $1); } else { @@ -141,9 +165,9 @@ foreach my $argv (@ARGV) { print scalar(@ARGV)." files read.\n" if $::opt_v and @ARGV > 1; -my @ls = sort { - $a->{category} cmp $b->{category} || $a->{in} cmp $b->{in} -} values %ls; +# --- Firstly we filter and sort as needed --- + +my @ls = values %ls; if ($::opt_f) { # filter out patches based on -f my $out; @@ -158,6 +182,24 @@ if ($::opt_f) { # filter out patches based on -f } @ls; } +@ls = sort { + $a->{category} cmp $b->{category} || $a->{in} cmp $b->{in} +} @ls; + + +# --- Handle special modes --- + +if ($::opt_4) { + print map { "p4 delete $_\n" } @removed if @removed; + print map { "p4 add $_\n" } @added if @added; + my @patches = grep { $_->{is_in} } @ls; + my %patched = map { ($_, 1) } map { keys %{$_->{out}} } @patches; + delete @patched{@added}; + my @patched = sort keys %patched; + print map { "p4 edit $_\n" } @patched if @patched; + exit 0; +} + if ($::opt_I) { my $n_patches = 0; my($in,$out); @@ -171,12 +213,16 @@ if ($::opt_I) { my @all_out = sort keys %all_out; my @missing = grep { ! -f $_ } @all_out; print "$n_patches patch files patch ".@all_out." files (".@missing." missing)\n"; + print "(use -v to list patches which patch 'missing' files)\n" + if @missing && !$::opt_v; if ($::opt_v and @missing) { print "Missing files:\n"; foreach $out (@missing) { printf " %-20s\t%s\n", $out, $all_out{$out}; } } + print "Added files: @added\n" if @added; + print "Removed files: @removed\n" if @removed; exit 0+@missing; } @@ -256,11 +302,27 @@ sub list_files_by_patch { $name = $ls->{in} unless defined $name; my @meta; if ($::opt_m) { - foreach(qw(Title From Msg-ID)) { - next unless $ls->{$_}; - my @list = sort keys %{$ls->{$_}}; - push @meta, sprintf "%7s: ", $_; - @list = map { "\"$_\"" } @list if $_ eq 'Title'; + my $meta; + foreach $meta (@show_meta) { + next unless $ls->{$meta}; + my @list = sort keys %{$ls->{$meta}}; + push @meta, sprintf "%7s: ", $meta; + if ($meta eq 'Title') { + @list = map { s/\[?PATCH\]?:?\s*//g; "\"$_\""; } @list + } + elsif ($meta eq 'From') { + # fix-up bizzare addresses from japan and ibm :-) + foreach(@list) { + s:\W+=?iso.*?<: <:; + s/\d\d-\w\w\w-\d{4}\s+\d\d:\S+\s*//; + } + } + elsif ($meta eq 'Msg-ID') { + my %from; # limit long threads to one msg-id per site + @list = map { + $from{(/@(.*?)>/ ? $1 : $_)}++ ? () : ($_); + } @list; + } push @meta, my_wrap(""," ", join(", ",@list)."\n"); } $name = "\n$name" if @meta and $name; diff --git a/Porting/pumpkin.pod b/Porting/pumpkin.pod index 5260e65..6706c6c 100644 --- a/Porting/pumpkin.pod +++ b/Porting/pumpkin.pod @@ -41,6 +41,10 @@ Subscribe by sending the message (in the body of your letter) to perl5-porters-request@perl.org . +Archives of the list are held at: + + http://www.rosat.mpe-garching.mpg.de/mailing-lists/perl-porters/ + =head1 How are Perl Releases Numbered? Perl version numbers are floating point numbers, such as 5.004. @@ -73,9 +77,10 @@ In addition, there may be "developer" sub-versions available. These are not official releases. They may contain unstable experimental features, and are subject to rapid change. Such developer sub-versions are numbered with sub-version numbers. For example, -version 5.004_04 is the 4'th developer version built on top of -5.004. It might include the _01, _02, and _03 changes, but it -also might not. Sub-versions are allowed to be subversive. +version 5.003_04 is the 4'th developer version built on top of +5.003. It might include the _01, _02, and _03 changes, but it +also might not. Sub-versions are allowed to be subversive. (But see +the next section for recent changes.) These sub-versions can also be used as floating point numbers, so you can do things such as @@ -100,6 +105,11 @@ way to distribute important bug fixes without waiting for the developers to untangle all the other problems in the current developer's release. +Trial releases of bug-fix maintenance releases are announced on +perl5-porters. Trial releases use the new subversion number (to avoid +testers installing it over the previous release) and include a 'local +patch' entry in patchlevel.h. + Watch for announcements of maintenance subversions in comp.lang.perl.announce. @@ -1157,14 +1167,14 @@ and/or fcntl() file locking. It's a mess. =back -=head1 AUTHOR - -Andy Dougherty . +=head1 AUTHORS -Additions by Chip Salzenberg . +Original author: Andy Dougherty doughera@lafcol.lafayette.edu . +Additions by Chip Salzenberg chip@perl.com and +Tim Bunce Tim.Bunce@ig.co.uk . All opinions expressed herein are those of the authorZ<>(s). =head1 LAST MODIFIED -$Id: pumpkin.pod,v 1.10.1.1 1997/06/10 20:46:47 timbo Exp $ +$Id: pumpkin.pod,v 1.13 1997/08/28 18:26:40 doughera Released $ diff --git a/README.vms b/README.vms index 9a6a712..4b8c29d 100644 --- a/README.vms +++ b/README.vms @@ -1,3 +1,383 @@ +Last Revised 11-September-1997 by Dan Sugalski +Originally by Charles Bailey + +* Intro + +The VMS port of Perl is as functionally complete as any other Perl port +(and as complete as the ports on some Unix systems). The Perl binaries +provide all the Perl system calls that are either available under VMS or +reasonably emulated. There are some incompatibilites in process handling +(e.g the fork/exec model for creating subprocesses doesn't do what you +might expect under Unix), mainly because VMS and Unix handle processes and +sub-processes very differently. + +There are still some unimplemented system functions, and of coursse we +could use modules implementing useful VMS system services, so if you'd like +to lend a hand we'd love to have you. Join the Perl Porting Team Now! + +The current sources and build procedures have been tested on a VAX using +VaxC and Dec C, and on an AXP using Dec C. If you run into problems with +other compilers, please let us know. + +There are issues with varions versions of Dec C, so if you're not running a +relatively modern version, check the Dec C issues section later on in this +document. + +* Other required software + +In addition to VMS, you'll need: + 1) A C compiler. Dec C for AXP, or VAX C, Dec C, or gcc for the + VAX. + 2) A make tool. Dec's MMS (v2.6 or later), or MadGoat's free MMS + analog MMK (available from ftp.madgoat.com/madgoat) both work + just fine. Gnu Make might work, but it's been so long since + anyone's tested it that we're not sure. MMK's free, though, so + go ahead and use that. + + +If you want to include socket support, you'll need a TCP stack and either +Dec C, or socket libraries. See the Socket Support topic for more details. + +* Compiling Perl + +>From the top level of the Perl source directory, do this: + +MMS/DESCRIP=[.VMS]DESCRIP.MMS + +If you're on an Alpha, add /Macro=("__AXP__=1","decc=1") +If you're using Dec C as your C compiler (you are on all alphas), add +/Macro=("decc=1") +If Vac C is your default C compiler and you want to use Dec C, add +/Macro=("CC=CC/DECC") (Don't forget the /macro=("decc=1") +If Dec C is your default C compiler and you want to use Vax C, add +/Macro=("CC=CC/VAXC") +If you want Socket support and are using the SOCKETSHR socket library, add +/Macro=("SOCKETSHR_SOCKETS=1") +If you want Socket support and are using the Dec C RTL socket interface +(You must be using Dec C for this), add /Macro=("DECC_SOCKETS=1") + +If you have multiple /macro= items, combine them together in one /Macro=() +switch, with all the options inside the parentheses separated by commas. + +Samples: + +VMS AXP, with Socketshr sockets: + +$MMS/DESCRIP=[.VMS]DESCRIP.MMS/Macro=("decc=1","__AXP__=1","SOCKETSHR_SOCKETS=1") + +VMS AXP with no sockets + +$MMS/DESCRIP=[.VMS]DESCRIP.MMS/Macro=("decc=1","__AXP__=1") + +VMS AXP with the Dec C RTL sockets + +$MMS/DESCRIP=[.VMS]/Macro=("decc=1","__AXP__=1","DECC_SOCKETS=1") + +VMS VAX with default system compiler, no sockets + +$MMS/DESCRIP=[.VMS]DESCRIP.MMS + +VMS VAX with Dec C compiler, no sockets + +$MMS/DESCRIP=[.VMS]DESCRIP.MMS/Macro=("CC=CC/DECC","decc=1") + +VMS VAX with Dec C compiler, Dec C RTL sockets + +$MMS/DESCRIP=[.VMS]DESCRIP.MMS/Macro=("CC=CC/DECC","decc=1","DECC_SOCKETS=1") + +VMS VAX with Dec C compiler, Socketshr sockets + +$MMS/DESCRIP=[.VMS]DESCRIP.MMS/Macro=("CC=CC/DECC","decc=1","SOCKETSHR_SOCKETS=1") + +Using Dec C is recommended over Vax C. The compiler is newer, and +supported. (Vax C was decommisioned around 1993) Various older versions had +some gotchas, so if you're using a version older than 5.2, check the Dec C +Issues section. + +We'll also point out that Dec C will get you at least a ten-fold increase +in line-oriented IO over Vax C. The optimizer is amazingly better, too. If +you can use Dec C, then you *really*, *really* should. + + +Once you issue your MMS command, sit back and wait. Perl should build and +link without a problem. If it doesn't, check the Gotchas to watch out for +section. If that doesn't help, send some mail to the VMSPERL mailing list. +Instructions are in the Mailing Lists section. + +* Testing Perl + +Once Perl has built cleanly, you need to test it to make sure things work. +This step is very important--there are always things that can go wrong +somehow and get you a dysfunctional Perl. + +Testing is very easy, though, as there's a full test suite in the perl +distribution. To run the tests, enter the *exact* MMS line you used to +compile Perl and add the word "test" to the end, like this: + +Compile Command: + +$MMS/DESCRIP=[.VMS]DESCRIP.MMS/Macro=("__AXP__=1","decc=1","DECCRTL_SOCKETS=1") + +Test Command: + +$MMS/DESCRIP=[.VMS]DESCRIP.MMS/Macro=("__AXP__=1","decc=1","DECCRTL_SOCKETS=1") test + +MMS will run all the tests. This may take some time, as there are a lot of +tests. If any tests fail, there will be a note made on-screen. At the end +of all the tests, a summary of the tests, the number passed and failed, and +the time taken will be displayed. + +If any tests fail, it means something's wrong with Perl. If the test suite +hangs (some tests can take upwards of two or three minutes, or more if +you're on an especially slow machine, depending on you machine speed, so +don't be hasty), then the test *after* the last one displayed failed. Don't +install Perl unless you're confident that you're OK. Regardless of how +confident you are, make a bug report to the VMSPerl mailing list. + +If one or more tests fail, you can get more info on the failure by issuing +this command sequence: + +$ SET DEFAULT [.T] +$ @[-.VMS]TEST .typ -v [.subdir]test.T + +where ".typ" is the file type of the Perl images you just built (if you +didn't do anything special, use .EXE), and "[.subdir]test.T" is the test +that failed. For example, with a normal Perl build, if the test indicated +that [.op]time failed, then you'd do this: + +$ SET DEFAULT [.T] +$ @[-.VMS]TEST .EXE -v [.OP]TIME.T + +When you send in a bug report for failed tests, please include the output +from this command, which is run from the main source directory: + +MCR []MINIPERL "-V" + +Note that "-V" really is a capital V in double quotes. This will dump out a +couple of screens worth of config info, and can help us diagnose the problem. + +* Cleaning up and starting fresh + +If you need to recompile from scratch, you have to make sure you clean up +first. There's a procedure to do it--enter the *exact* MMS line you used to +compile and add "realclean" at the end, like this: + +Compile Command: + +$MMS/DESCRIP=[.VMS]DESCRIP.MMS/Macro=("__AXP__=1","decc=1","DECCRTL_SOCKETS=1") + +Cleanup Command: + +$MMS/DESCRIP=[.VMS]DESCRIP.MMS/Macro=("__AXP__=1","decc=1","DECCRTL_SOCKETS=1") realclean + +If you don't do this, things may behave erratically. They might not, too, +so it's best to be sure and do it. + +* Installing Perl + +There are several steps you need to take to get Perl installed and +running. At some point we'll have a working install in DESCRIP.MMS, but for +right now the procedure's manual, and goes like this. + +1) Create a directory somewhere and define the concealed logical PERL_ROOT +to point to it. For example, DEFINE/TRANS=(CONC,TERM) PERL_ROOT dka200:[perl.] + +2) Copy perl.exe into PERL_ROOT:[000000] + +3) Copy everything in [.LIB] and [.UTILS] (including all the +subdirectories!) to PERL_ROOT:[LIB] and PERL_ROOT:[UTILS]. + +4) Either copy PERLSHR.EXE to SYS$SHARE, or to somewhere globally accessble +and define the logical PERLSHR to point to it (DEFINE PERLSHR +PERL_ROOT:[000000]PERLSHR.EXE or something like that). The PerlShr image +should have W:RE protections on it. (Just W:E triggers increased security in +the image activator. Not a huge problem, but Perl will need to have any +other shared image it accesses INSTALLed. It's a huge pain, so don't unless +you know what you're doing) + +5) Either define the symbol PERL somewhere, such as +SYS$MANAGER:SYLOGIN.COM, to be "PERL :== $PERL_ROOT:[000000]PERL.EXE", or +install Perl into DCLTABLES.EXE )Check out the section "Installing Perl +into DCLTABLES" for more info), or put the image in a directory that's in +your DCL$PATH (if you're using VMS 6.2 or higher). + +6) Optionally define the command PERLDOC as +PERLDOC :== $PERL_ROOT:[000000]PERL PERL_ROOT:[LIB.POD]PERLDOC.COM -T + +7) Optionally define the command PERLBUG (the Perl bug report generator) as +PERLBUG :== $PERL_ROOT:[000000]PERL PERL_ROOT:[LIB]PERLBUG.COM" + +* Installing Perl into DCLTABLES + +Courtesy of Brad Hughes: + +Put the following, modified to reflect where your .exe is, in PERL.CLD: + +define verb perl +image perl_root:[exe]perl.exe +cliflags (foreign) + +and then + +$ set command perl /table=sys$common:[syslib]dcltables.exe - + /output=sys$common:[syslib]dcltables.exe +$ install replace sys$common:[syslib]dcltables.exe + +and you don't need perl :== $perl_root:[exe]perl.exe. + +* Changing compile-time things + +Most of the user-definable features of Perl are enabled or disabled in +[.VMS]CONFIG.VMS. There's code in there to Do The Right Thing, but that may +end up being the wrong thing for you. Make sure you understand what you're +doing, since changes here can get you a busted perl. + +Odds are that there's nothing here to change, unless you're on a version of +VMS later than 6.2 and Dec C later than 5.6. Even if you are, the correct +values will still be chosen, most likely. Poking around here should be +unnecessary. + +The one exception is the various *DIR install locations. Changing those +requires changes in genconfig.pl as well. Be really careful if you need to +change these,a s they can cause some fairly subtle problems. + +* Extra things in the Perl distribution + +In addition to the standard stuff that gets installed, there are two +optional extensions, DCLSYM and STDIO, that are handy. Instructions for +these two modules are in [.VMS.EXT.DCLSYM] and [.VMS.EXT.STDIO], +respectively. + +* Socket Support + +Perl includes a number of functions for IP sockets, which are available if +you choose to compile Perl with socket support. (See the section Compiling +Perl for more info on selecting a socket stack) Since IP networking is an +optional addition to VMS, there are several different IP stacks +available. How well integrated they are into the system depends on the +stack, your version of VMS, and the version of your C compiler. + +The most portable solution uses the SOCKETSHR library. In combination with +either UCX or NetLib, this supports all the major TCP stacks (Multinet, +Pathways, TCPWare, UCX, and CMU) on all versions of VMS Perl runs on, with +all the compilers on both VAX and Alpha. The socket interface is also +consistent across versions of VMS and C compilers. It has a problem with +UDP sockets when used with Multinet, though, so you should be aware of +that. + +The other solution available is to use the socket routines built into Dec +C. Which routines are available depend on the version of VMS you're +running, and require proper UCX emulation by your TCP/IP vendor. +Relatively current versions of Multinet, TCPWare, Pathway, and UCX all +provide the required libraries--check your manuals or release notes to see +if your version is new enough. + +* Reporting Bugs + +If you come across what you think might be a bug in Perl, please report +it. There's a script in PERL_ROOT:[UTILS], perlbug, that walks you through +the process of creating a bug report. This script includes details of your +installation, and is very handy. Completed bug reports should go to +PERLBUG@PERL.COM. + +* Gotchas to watch out for + +Probably the single biggest gotcha in compiling Perl is giving the wrong +switches to MMS/MMK when you build. If Perl's building oddly, double-check +your switches. If you're on a VAX, be sure to add a /Macro=("decc=1") if +you're using Dec C, and if you're on an alpha and using MMS, you'll need a +/Macro=("__AXP__=1") + +The next big gotcha is directory depth. Perl can create directories four +and five levels deep during the build, so you don't have to be too deep to +start to hit the RMS 8 level point. It's best to do a +$DEFINE/TRANS=(CONC,TERM) PERLSRC disk:[dir.dir.dir.perldir.]" (note the +trailing period) and $SET DEFAULT PERLSRC:[000000] before building. Perl +modules can be just as bad (or worse), so watch out for them, too. + +Finally, the third thing that bites people is leftover pieces from a failed +build. If things go wrong, make sure you do a "(MMK|MMS|make) realclean" +before you rebuild. + +* Dec C issues + +Note to DECC users: Some early versions (pre-5.2, some pre-4. If you're Dec +C 5.x or higher, with current patches if anym you're fine) of the DECCRTL +contained a few bugs which affect Perl performance: + - Newlines are lost on I/O through pipes, causing lines to run together. + This shows up as RMS RTB errors when reading from a pipe. You can + work around this by having one process write data to a file, and + then having the other read the file, instead of the pipe. This is + fixed in version 4 of DECC. + - The modf() routine returns a non-integral value for some values above + INT_MAX; the Perl "int" operator will return a non-integral value in + these cases. This is fixed in version 4 of DECC. + - On the AXP, if SYSNAM privilege is enabled, the CRTL chdir() routine + changes the process default device and directory permanently, even + though the call specified that the change should not persist after + Perl exited. This is fixed by DEC CSC patch AXPACRT04_061. + +* Mailing Lists + +There are several mailing lists available to the Perl porter. For VMS +specific issues (including both Perl questions and installation problems) +there is the VMSPERL mailing list. It's usually a low-volume (10-12 +messages a week) mailing list. + +The subscription address is VMSPERL-REQUEST@NEWMAN.UPENN.EDU. Send a mail +message with just the words SUBSCRIBE VMSPERL in the body of the message. + +The VMSPERL mailing list address is VMSPERL@NEWMAN.UPENN.EDU. Any mail +sent there gets echoed to all subscribers of the list. + +The Perl5-Porters list is for anyone involved in porting Perl to a +platform. This includes you, if you want to participate. It's a high-volume +list (60-100 messages a day during active development times), so be sure +you want to be there. The subscription address is +Perl5-Porters-request@perl.org. Send a message with just the word SUBSCRIBE +in the body. The posting address is Perl5-Porters@perl.org. + +* Acknowledgements + +A real big thanks needs to go to Charles Bailey +, who is ultimately responsible for Perl 5.004 +running on VMS. Without him, nothing the rest of us have done would be at +all important. + +There are, of course, far too many people involved in the porting and testing +of Perl to mention everyone who deserves it, so please forgive us if we've +missed someone. That said, special thanks are due to the following: + Tim Adye + for the VMS emulations of getpw*() + David Denholm + for extensive testing and provision of pipe and SocketShr code, + Mark Pizzolato + for the getredirection() code + Rich Salz + for readdir() and related routines + Peter Prymmer + for extensive contributions to recent version support, + development of VMS-specific extensions, and dissemination + of information about VMS Perl, + the Stanford Synchrotron Radiation Laboratory and the + Laboratory of Nuclear Studies at Cornell University for + the the opportunity to test and develop for the AXP, +and to the entire VMSperl group for useful advice and suggestions. In +addition the perl5-porters deserve credit for their creativity and +willingness to work with the VMS newcomers. Finally, the greatest debt of +gratitude is due to Larry Wall , for having the ideas which +have made our sleepless nights possible. + +Thanks, +The VMSperl group + + +--------------------------------------------------------------------------- +[Here's the pre-5.004_04 version of README.vms, for the record.] + Last revised: 19-Jan-1996 by Charles Bailey bailey@genetics.upenn.edu The VMS port of Perl is still under development. At this time, the Perl diff --git a/av.c b/av.c index 6b4c03d..4a87eaf 100644 --- a/av.c +++ b/av.c @@ -15,15 +15,15 @@ #include "EXTERN.h" #include "perl.h" -static void av_reify _((AV* av)); - -static void +void av_reify(av) AV* av; { I32 key; SV* sv; - + + if (AvREAL(av)) + return; key = AvMAX(av) + 1; while (key > AvFILL(av) + 1) AvARRAY(av)[--key] = &sv_undef; @@ -324,6 +324,9 @@ register AV *av; SvPVX(av) = (char*)AvALLOC(av); } AvFILL(av) = -1; + + if (SvRMAGICAL(av)) + mg_clear((SV*)av); } void diff --git a/configpm b/configpm index 8ea1420..0c6a965 100755 --- a/configpm +++ b/configpm @@ -180,6 +180,9 @@ ENDOFSET print CONFIG <<'ENDOFTAIL'; +# avoid Config..Exporter..UNIVERSAL search for DESTROY then AUTOLOAD +sub DESTROY { } + tie %Config, 'Config'; 1; diff --git a/doop.c b/doop.c index 763b1a9..571a9aa 100644 --- a/doop.c +++ b/doop.c @@ -440,6 +440,7 @@ SV *right; break; } } + SvTAINT(sv); } OP * diff --git a/eg/sysvipc/ipcsem b/eg/sysvipc/ipcsem index 4d871b9..e0dc551 100644 --- a/eg/sysvipc/ipcsem +++ b/eg/sysvipc/ipcsem @@ -18,7 +18,7 @@ print "semaphore id: $id\n"; if ($signal) { while () { print "Signalling\n"; - unless (semop($id, 0, pack("sss", 0, 1, 0))) { + unless (semop($id, pack("sss", 0, 1, 0))) { die "Can't signal semaphore: $!\n"; } } @@ -26,7 +26,7 @@ if ($signal) { else { $SIG{'INT'} = $SIG{'QUIT'} = "leave"; for (;;) { - unless (semop($id, 0, pack("sss", 0, -1, 0))) { + unless (semop($id, pack("sss", 0, -1, 0))) { die "Can't wait for semaphore: $!\n"; } print "Unblocked\n"; diff --git a/emacs/cperl-mode.el b/emacs/cperl-mode.el index 017a7a2..b00d77a 100644 --- a/emacs/cperl-mode.el +++ b/emacs/cperl-mode.el @@ -32,7 +32,7 @@ ;;; Corrections made by Ilya Zakharevich ilya@math.mps.ohio-state.edu ;;; XEmacs changes by Peter Arius arius@informatik.uni-erlangen.de -;; $Id: cperl-mode.el,v 1.33 1997/03/14 06:45:51 ilya Exp ilya $ +;; $Id: cperl-mode.el,v 1.39 1997/10/14 08:28:00 ilya Exp ilya $ ;;; To use this mode put the following into your .emacs file: @@ -53,7 +53,7 @@ ;;; Additional useful commands to put into your .emacs file: ;; (setq auto-mode-alist -;; (append '(("\\.[pP][Llm]$" . perl-mode)) auto-mode-alist )) +;; (append '(("\\.\\([pP][Llm]\\|al\\)$" . perl-mode)) auto-mode-alist )) ;; (setq interpreter-mode-alist (append interpreter-mode-alist ;; '(("miniperl" . perl-mode)))) @@ -399,7 +399,7 @@ ;;;; `cperl-use-syntax-table-text-property'. ;;;; After 1.32.3 -;;; We scan for s{}[] as well. +;;; We scan for s{}[] as well (in simplest situations). ;;; We scan for $blah'foo as well. ;;; The default is to use `syntax-table' text property if Emacs is good enough. ;;; `cperl-lineup' is put on C-M-| (=C-M-S-\\). @@ -411,6 +411,58 @@ ;;; Generation of Class Hierarchy was broken due to a bug in `x-popup-menu' ;;; in 19.34. +;;;; After 1.33: +;;; my,local highlight vars after {} too. +;;; TAGS could not be created before imenu was loaded. +;;; `cperl-indent-left-aligned-comments' created. +;;; Logic of `cperl-indent-exp' changed a little bit, should be more +;;; robust w.r.t. multiline strings. +;;; Recognition of blah'foo takes into account strings. +;;; Added '.al' to the list of Perl extensions. +;;; Class hierarchy is "mostly" sorted (need to rethink algorthm +;;; of pruning one-root-branch subtrees to get yet better sorting.) +;;; Regeneration of TAGS was busted. +;;; Can use `syntax-table' property when generating TAGS +;;; (governed by `cperl-use-syntax-table-text-property-for-tags'). + +;;;; After 1.35: +;;; Can process several =pod/=cut sections one after another. +;;; Knows of `extproc' when under `emx', indents with `__END__' and `__DATA__'. +;;; `cperl-under-as-char' implemented (XEmacs people like broken behaviour). +;;; Beautifier for regexps fixed. +;;; `cperl-beautify-level', `cperl-contract-level' coded +;;; +;;;; Emacs's 20.2 problems: +;;; `imenu.el' has bugs, `imenu-add-to-menubar' does not work. +;;; Couple of others problems with 20.2 were reported, my ability to check/fix +;;; them is very reduced now. + +;;;; After 1.36: +;;; 'C-M-|' in XEmacs fixed + +;;;; After 1.37: +;;; &&s was not recognized as start of regular expression; +;;; Will "preprocess" the contents of //e part of s///e too; +;;; What to do with s# blah # foo #e ? +;;; Should handle s;blah;foo;; better. +;;; Now the only known problems with regular expression recognition: +;;;;;;; s/bar/ - different delimiters (end ignored) +;;;;;;; s/foo/\\bar/ - backslash at start of subst (made into one chunk) +;;;;;;; s/foo// - empty subst (made into one chunk + '/') +;;;;;;; s/foo/(bar)/ - start-group at start of subst (internal group will not match backwards) + +;;;; After 1.38: +;;; We highlight closing / of s/blah/foo/e; +;;; This handles s# blah # foo #e too; +;;; s//blah/, s///, s/blah// works again, and s#blah## too, the algorithm +;;; is much simpler now; +;;; Next round of changes: s\\\ works, s/foo/, +;;; comments between the first and the second part allowed +;;; Another problem discovered: +;;;;;;; s[foo] e - e part delimited by different <> (will not match) +;;; `cperl-find-pods-heres' somehow maybe called when string-face is undefined +;;; - put a stupid workaround for 20.1 + (defconst cperl-xemacs-p (string-match "XEmacs\\|Lucid" emacs-version)) (defvar cperl-extra-newline-before-brace nil @@ -474,7 +526,8 @@ Can be overwritten by `cperl-hairy' if nil.") Can be overwritten by `cperl-hairy' if nil.") (defvar cperl-electric-parens-string "({[]})<" - "*String of parentheses that should be electric in CPerl.") + "*String of parentheses that should be electric in CPerl. +Closing ones are electric only if the region is highlighted.") (defvar cperl-electric-parens nil "*Non-nil (and non-null) means parentheses should be electric in CPerl. @@ -488,10 +541,6 @@ Can be overwritten by `cperl-hairy' if nil.") "*Not-nil means that electric parens look for active mark. Default is yes if there is visual feedback on mark.") -(defvar cperl-electric-parens-mark (and window-system transient-mark-mode) - "*Not-nil means that electric parens look for active mark. -Default is yes if there is visual feedback on mark.") - (defvar cperl-electric-linefeed nil "*If true, LFD should be hairy in CPerl, otherwise C-c LFD is hairy. In any case these two mean plain and hairy linefeeds together. @@ -551,11 +600,14 @@ May require patched `imenu' and `imenu-go'.") Older version of this page was called `perl5', newer `perl'.") (defvar cperl-use-syntax-table-text-property - (and (not cperl-xemacs-p) - (string< "19.34.94" emacs-version)) ; Not all .94 are good, but anyway + (boundp 'parse-sexp-lookup-properties) "*Non-nil means CPerl sets up and uses `syntax-table' text property.") -(defvar cperl-scan-files-regexp "\\.\\([Pp][Llm]\\|xs\\)$" +(defvar cperl-use-syntax-table-text-property-for-tags + cperl-use-syntax-table-text-property + "*Non-nil means: set up and use `syntax-table' text property generating TAGS.") + +(defvar cperl-scan-files-regexp "\\.\\([pP][Llm]\\|xs\\)$" "*Regexp to match files to scan when generating TAGS.") (defvar cperl-noscan-files-regexp "/\\(\\.\\.?\\|SCCS\\|RCS\\|blib\\)$" @@ -565,6 +617,13 @@ Older version of this page was called `perl5', newer `perl'.") "*indentation used when beautifying regexps. If `nil', the value of `cperl-indent-level' will be used.") +(defvar cperl-indent-left-aligned-comments t + "*Non-nil means that the comment starting in leftmost column should indent.") + +(defvar cperl-under-as-char t + "*Non-nil means that the _ (underline) should be treated as word char.") + + ;;; Short extra-docs. @@ -798,11 +857,14 @@ progress indicator for indentation (with `imenu' loaded). (put-text-property (max (point-min) (1- from)) to cperl-do-not-fontify t)) +(defvar cperl-mode-hook nil + "Hook run by `cperl-mode'.") + ;;; Probably it is too late to set these guys already, but it can help later: (setq auto-mode-alist - (append '(("\\.[pP][Llm]$" . perl-mode)) auto-mode-alist )) + (append '(("\\.\\([pP][Llm]\\|al\\)$" . perl-mode)) auto-mode-alist )) (and (boundp 'interpreter-mode-alist) (setq interpreter-mode-alist (append interpreter-mode-alist '(("miniperl" . perl-mode))))) @@ -847,7 +909,8 @@ progress indicator for indentation (with `imenu' loaded). (cperl-define-key "\C-c\C-k" 'cperl-toggle-abbrev) (cperl-define-key "\C-c\C-e" 'cperl-toggle-electric) (cperl-define-key "\e\C-q" 'cperl-indent-exp) ; Usually not bound - (cperl-define-key [?\C-\M-\|] 'cperl-lineup) + (cperl-define-key [?\C-\M-\|] 'cperl-lineup + [(control meta |)]) ;;(cperl-define-key "\M-q" 'cperl-fill-paragraph) ;;(cperl-define-key "\e;" 'cperl-indent-for-comment) (cperl-define-key "\177" 'cperl-electric-backspace) @@ -883,6 +946,7 @@ progress indicator for indentation (with `imenu' loaded). 'indent-for-comment 'cperl-indent-for-comment cperl-mode-map global-map))) +(defvar cperl-menu) (condition-case nil (progn (require 'easymenu) @@ -897,6 +961,10 @@ progress indicator for indentation (with `imenu' loaded). ["Line up a construction" cperl-lineup (cperl-use-region-p)] ["Beautify a regexp" cperl-beautify-regexp cperl-use-syntax-table-text-property] + ["Beautify a group in regexp" cperl-beautify-level + cperl-use-syntax-table-text-property] + ["Contract a group in regexp" cperl-contract-level + cperl-use-syntax-table-text-property] "----" ["Indent region" cperl-indent-region (cperl-use-region-p)] ["Comment region" cperl-comment-region (cperl-use-region-p)] @@ -936,7 +1004,7 @@ progress indicator for indentation (with `imenu' loaded). (cperl-write-tags nil t t t) t] ["Add tags for Perl files in (sub)directories" (cperl-write-tags nil nil t t) t]) - ["Recalculate PODs and HEREs" cperl-find-pods-heres t] + ["Recalculate \"hard\" constructions" cperl-find-pods-heres t] ["Define word at point" imenu-go-find-at-position (fboundp 'imenu-go-find-at-position)] ["Help on function" cperl-info-on-command t] @@ -992,7 +1060,8 @@ The expansion is entirely correct because it uses the C preprocessor." (modify-syntax-entry ?# "<" cperl-mode-syntax-table) (modify-syntax-entry ?' "\"" cperl-mode-syntax-table) (modify-syntax-entry ?` "\"" cperl-mode-syntax-table) - (modify-syntax-entry ?_ "w" cperl-mode-syntax-table) + (if cperl-under-as-char + (modify-syntax-entry ?_ "w" cperl-mode-syntax-table)) (modify-syntax-entry ?: "_" cperl-mode-syntax-table) (modify-syntax-entry ?| "." cperl-mode-syntax-table) (setq cperl-string-syntax-table (copy-syntax-table cperl-mode-syntax-table)) @@ -1014,6 +1083,9 @@ The expansion is entirely correct because it uses the C preprocessor." ;; provide an alias for working with emacs 19. the perl-mode that comes ;; with it is really bad, and this lets us seamlessly replace it. (fset 'perl-mode 'cperl-mode) +(defvar cperl-faces-init) +;; Fix for msb.el +(defvar cperl-msb-fixed nil) (defun cperl-mode () "Major mode for editing Perl code. Expression and list commands understand all C brackets. @@ -1229,7 +1301,8 @@ with no args." (if cperl-use-syntax-table-text-property (progn (make-variable-buffer-local 'parse-sexp-lookup-properties) - (setq parse-sexp-lookup-properties t))) + ;; Do not introduce variable if not needed, we check it! + (set 'parse-sexp-lookup-properties t))) (or (fboundp 'cperl-old-auto-fill-mode) (progn (fset 'cperl-old-auto-fill-mode (symbol-function 'auto-fill-mode)) @@ -1266,8 +1339,6 @@ with no args." nil nil '(gud-perldb-history . 1)))) -;; Fix for msb.el -(defvar cperl-msb-fixed nil) (defun cperl-msb-fix () ;; Adds perl files to msb menu, supposes that msb is already loaded @@ -1881,7 +1952,9 @@ Returns nil if line starts inside a string, t if in a comment." '(pod here-doc here-doc-delim format)) ;; before start of POD - whitespace found since do not have 'pod! (and (looking-at "[ \t]*\n=") - (error "Spaces before pod section!"))) + (error "Spaces before pod section!")) + (and (not cperl-indent-left-aligned-comments) + (looking-at "^#"))) nil (beginning-of-line) (let ((indent-point (point)) @@ -2384,20 +2457,118 @@ Returns true if comment is found." 'syntax-table cperl-string-syntax-table)) (cperl-protect-defun-start bb e)))) +(defun cperl-forward-re (is-2arg set-st st-l err-l argument + &optional ostart oend) + ;; Unfinished + ;; Works *before* syntax recognition is done + ;; May modify syntax-type text property if the situation is too hard + (let (b starter ender st i i2) + (skip-chars-forward " \t") + ;; ender means matching-char matcher. + (setq b (point) + starter (char-after b) + ;; ender: + ender (cdr (assoc starter '(( ?\( . ?\) ) + ( ?\[ . ?\] ) + ( ?\{ . ?\} ) + ( ?\< . ?\> ) + )))) + ;; What if starter == ?\\ ???? + (if set-st + (if (car st-l) + (setq st (car st-l)) + (setcar st-l (make-syntax-table)) + (setq i 0 st (car st-l)) + (while (< i 256) + (modify-syntax-entry i "." st) + (setq i (1+ i))) + (modify-syntax-entry ?\\ "\\" st))) + (setq set-st t) + ;; Whether we have an intermediate point + (setq i nil) + ;; Prepare the syntax table: + (and set-st + (if (not ender) ; m/blah/, s/x//, s/x/y/ + (modify-syntax-entry starter "$" st) + (modify-syntax-entry starter (concat "(" (list ender)) st) + (modify-syntax-entry ender (concat ")" (list starter)) st))) + (condition-case bb + (progn + (if (and (eq starter (char-after (cperl-1+ b))) + (not ender)) + ;; $ has TeXish matching rules, so $$ equiv $... + (forward-char 2) + (set-syntax-table st) + (forward-sexp 1) + (set-syntax-table cperl-mode-syntax-table) + ;; Now the problem is with m;blah;; + (and (not ender) + (eq (preceding-char) + (char-after (- (point) 2))) + (save-excursion + (forward-char -2) + (= 0 (% (skip-chars-backward "\\\\") 2))) + (forward-char -1))) + (and is-2arg ; Have trailing part + (not ender) + (eq (following-char) starter) ; Empty trailing part + (if (eq (char-syntax (following-char)) ?.) + (setq is-2arg nil) ; Ignore the tail + ;; Make trailing letter into punctuation + (setq is-2arg nil) ; Ignore the tail + (put-text-property (point) (1+ (point)) + 'syntax-table cperl-st-punct) + (put-text-property (point) (1+ (point)) 'rear-nonsticky t))) + (if is-2arg ; Not number => have second part + (progn + (setq i (point) i2 i) + (if ender + (if (eq (char-syntax (following-char)) ?\ ) + (progn + (while (looking-at "\\s *#") + (beginning-of-line 2)) + (skip-chars-forward " \t\n\f") + (setq i2 (point)))) + (forward-char -1)) + (modify-syntax-entry starter (if (eq starter ?\\) "\\" ".") st) + (if ender (modify-syntax-entry ender "." st)) + (setq set-st nil) + (setq + ender + (cperl-forward-re nil t st-l err-l argument starter ender) + ender (nth 2 ender))))) + (error (goto-char (point-max)) + (message + "End of `%s%s%c ... %c' string not found: %s" + argument + (if ostart (format "%c ... %c" ostart (or oend ostart)) "") + starter (or ender starter) bb) + (or (car err-l) (setcar err-l b)))) + (if set-st + (progn + (modify-syntax-entry starter (if (eq starter ?\\) "\\" ".") st) + (if ender (modify-syntax-entry ender "." st)))) + (list i i2 ender starter))) + (defun cperl-find-pods-heres (&optional min max) - "Scans the buffer for POD sections and here-documents. + "Scans the buffer for hard-to-parse Perl constructions. If `cperl-pod-here-fontify' is not-nil after evaluation, will fontify the sections using `cperl-pod-head-face', `cperl-pod-face', `cperl-here-face'." (interactive) (or min (setq min (point-min))) (or max (setq max (point-max))) - (let (face head-face here-face b e bb tag qtag err b1 e1 argument st i c + (let (face head-face here-face b e bb tag qtag b1 e1 argument i c tail state (cperl-pod-here-fontify (eval cperl-pod-here-fontify)) (case-fold-search nil) (inhibit-read-only t) (buffer-undo-list t) (modified (buffer-modified-p)) (after-change-functions nil) - (state-point (point-min)) state + (state-point (point-min)) + (st-l '(nil)) (err-l '(nil)) i2 + ;; Somehow font-lock may be not loaded yet... + (font-lock-string-face (if (boundp 'font-lock-string-face) + font-lock-string-face + 'font-lock-string-face)) (search (concat "\\(\\`\n?\\|\n\n\\)=" @@ -2434,12 +2605,16 @@ the sections using `cperl-pod-head-face', `cperl-pod-face', "\\$\\(['{]\\)" "\\|" ;; 1+6+2+1+1+2+1=14 extra () before this: - "\\(\\") (progn (message "=cut is not preceded by a pod section") - (or err (setq err (point)))) + (or (car err-l) (setcar err-l (point)))) (beginning-of-line) (setq b (point) bb b) (or (re-search-forward "\n\n=cut\\>" max 'toend) (progn (message "Cannot find the end of a pod section") - (or err (setq err b)))) + (or (car err-l) (setcar err-l b)))) (beginning-of-line 2) ; An empty line after =cut is not POD! (setq e (point)) (put-text-property b e 'in-pod t) @@ -2499,7 +2679,9 @@ the sections using `cperl-pod-head-face', `cperl-pod-face', (match-beginning 1) (match-end 1) 'face head-face)))) (cperl-commentify bb e nil) - (goto-char e))) + (goto-char e) + (or (eq e (point-max)) + (forward-char -1)))) ; Prepare for immediate pod start. ;; Here document ;; We do only one here-per-line ;; 1 () ahead @@ -2548,7 +2730,7 @@ the sections using `cperl-pod-head-face', `cperl-pod-face', (cperl-commentify b e1 nil) (cperl-put-do-not-fontify b (match-end 0))) (t (message "End of here-document `%s' not found." tag) - (or err (setq err b)))))) + (or (car err-l) (setcar err-l b)))))) ;; format ((match-beginning 8) ;; 1+6=7 extra () before this: @@ -2587,7 +2769,7 @@ the sections using `cperl-pod-head-face', `cperl-pod-face', (cperl-commentify (point) (+ (point) 2) nil) (cperl-put-do-not-fontify (point) (+ (point) 2))) (message "End of format `%s' not found." name) - (or err (setq err b))) + (or (car err-l) (setcar err-l b))) (forward-line) (put-text-property b (point) 'syntax-type 'format) ;;; (cond ((re-search-forward (concat "^[.;]$") max 'toend) @@ -2604,23 +2786,29 @@ the sections using `cperl-pod-head-face', `cperl-pod-face', ;; Regexp: ((or (match-beginning 10) (match-beginning 11)) ;; 1+6+2=9 extra () before this: - ;; "\\<\\(qx?\\|[my]\\)\\>" + ;; "\\<\\(q[wxq]?\\|[msy]\\|tr\\)\\>" + ;; "\\|" + ;; "\\([?/]\\)" ; /blah/ or ?blah? (setq b1 (if (match-beginning 10) 10 11) argument (buffer-substring (match-beginning b1) (match-end b1)) b (point) i b c (char-after (match-beginning b1)) - bb (or - (memq (char-after (1- (match-beginning b1))) - '(?\$ ?\@ ?\% ?\& ?\*)) - (and - (eq (char-after (1- (match-beginning b1))) ?-) - (eq (char-after (match-beginning b1)) ?s)))) + bb (char-after (1- (match-beginning b1))) ; tmp holder + bb (and ; user variables/whatever + (match-beginning 10) + (or + (memq bb '(?\$ ?\@ ?\% ?\*)) + (and (eq bb ?-) (eq c ?s)) ; -s file test + (and (eq bb ?\&) ; &&m/blah/ + (not (eq (char-after + (- (match-beginning b1) 2)) + ?\&)))))) (or bb (if (eq b1 11) ; bare /blah/ or ?blah? (setq argument "" - bb + bb ; Not a regexp? (progn (goto-char (match-beginning b1)) (cperl-backward-to-noncomment (point-min)) @@ -2635,7 +2823,7 @@ the sections using `cperl-pod-head-face', `cperl-pod-face', (progn (forward-sexp -1) (looking-at - "\\(while\\|if\\|unless\\|until\\|and\\|or\\|not\\|xor\\|split\\|grep\\|map\\)\\>"))) + "\\(while\\|if\\|unless\\|until\\|and\\|or\\|not\\|xor\\|split\\|grep\\|map\\|print\\)\\>"))) (and (eq (preceding-char) ?.) (eq (char-after (- (point) 2)) ?.)) (bobp)))) @@ -2647,83 +2835,32 @@ the sections using `cperl-pod-head-face', `cperl-pod-face', (if (or bb (nth 3 state) (nth 4 state)) (goto-char i) (skip-chars-forward " \t") - ;; qtag means two-argument matcher, may be reset to - ;; 2 or 3 later if some special quoting is needed. - (setq b (point) - tag (char-after b) - qtag (if (string-match "^\\([sy]\\|tr\\)$" argument) t) - e1 (cdr (assoc tag '(( ?\( . ?\) ) - ( ?\[ . ?\] ) - ( ?\{ . ?\} ) - ( ?\< . ?\> ) - )))) - ;; What if tag == ?\\ ???? - (or st - (progn - (setq st (make-syntax-table) i 0) - (while (< i 256) - (modify-syntax-entry i "." st) - (setq i (1+ i))) - (modify-syntax-entry ?\\ "\\" st))) - ;; Whether we have an intermediate point - (setq i nil) - ;; Prepare the syntax table: - (cond - ;; $ has TeXish matching rules, so $$ equiv $... - ((and qtag - (not e1) - (eq tag (char-after (cperl-1+ b))) - (eq tag (char-after (+ 2 b)))) - (setq qtag 3)) ; s/// - ((and qtag - (not e1) - (eq tag (char-after (cperl-1+ b)))) - (setq qtag nil)) ; s//blah/, will work anyway - ((and (not e1) - (eq tag (char-after (cperl-1+ b)))) - (setq qtag 2)) ; m// - ((not e1) - (modify-syntax-entry tag "$" st)) ; m/blah/, s/x//, s/x/y/ - (t ; s{}(), m[] - (modify-syntax-entry tag (concat "(" (list e1)) st) - (modify-syntax-entry e1 (concat ")" (list tag)) st))) - (if (numberp qtag) - (forward-char qtag) - (condition-case bb - (progn - (set-syntax-table st) - (forward-sexp 1) ; Wrong if m// - taken care of... - (if qtag - (if e1 - (progn - (setq i (point)) - (set-syntax-table cperl-mode-syntax-table) - (forward-sexp 1)) ; Should be smarter? - ;; "$" has funny matching rules - (if (/= (char-after (- (point) 2)) - (preceding-char)) - (progn - ;; Commenting \\ is dangerous, what about ( ? - (if (eq (following-char) ?\\) nil - (setq i (point))) - (forward-char -1) - (forward-sexp 1))) - ))) - (error (goto-char (point-max)) - (message - "End of `%s%c ... %c' string not found: %s" - argument tag (or e1 tag) bb) - (or err (setq err b))))) - (set-syntax-table cperl-mode-syntax-table) + ;; qtag means two-arg matcher, may be reset to + ;; 2 or 3 later if some special quoting is needed. + ;; e1 means matching-char matcher. + (setq b (point) + i (cperl-forward-re + (string-match "^\\([sy]\\|tr\\)$" argument) + t st-l err-l argument) + i2 (nth 1 i) ; start of the second part + e1 (nth 2 i) ; ender, true if matching second part + i (car i) ; intermediate point + tail (if (and i (not e1)) (1- (point)))) + ;; Commenting \\ is dangerous, what about ( ? + (and i tail + (eq (char-after i) ?\\) + (setq i nil tail nil)) (if (null i) (cperl-commentify b (point) t) (cperl-commentify b i t) - (if (looking-at "\\sw*e") nil ; s///e - (cperl-commentify i (point) t))) + (if (looking-at "\\sw*e") ; s///e + (cperl-find-pods-heres i2 (1- (point))) + (cperl-commentify i2 (point) t) + (setq tail nil))) (if (eq (char-syntax (following-char)) ?w) - (forward-word 1)) ; skip modifiers s///s - (modify-syntax-entry tag "." st) - (if e1 (modify-syntax-entry e1 "." st)))) + (progn + (forward-word 1) ; skip modifiers s///s + (if tail (cperl-commentify tail (point) t)))))) ((match-beginning 13) ; sub with prototypes (setq b (match-beginning 0)) (if (memq (char-after (1- b)) @@ -2737,6 +2874,8 @@ the sections using `cperl-pod-head-face', `cperl-pod-face', ;; Mark as string (cperl-commentify (match-beginning 13) (match-end 13) t)) (goto-char (match-end 0)))) + ;; 1+6+2+1+1+2=13 extra () before this: + ;; "\\$\\(['{]\\)" ((and (match-beginning 14) (eq (preceding-char) ?\')) ; $' (setq b (1- (point)) @@ -2748,13 +2887,38 @@ the sections using `cperl-pod-head-face', `cperl-pod-face', (put-text-property (1- b) b 'syntax-table cperl-st-punct) (put-text-property (1- b) b 'rear-nonsticky t))) (goto-char (1+ b))) + ;; 1+6+2+1+1+2=13 extra () before this: + ;; "\\$\\(['{]\\)" ((match-beginning 14) ; ${ (setq bb (match-beginning 0)) (put-text-property bb (1+ bb) 'syntax-table cperl-st-punct) (put-text-property bb (1+ bb) 'rear-nonsticky t)) - (t ; old $abc'efg syntax - (setq bb (match-end 0)) - (put-text-property (1- bb) bb 'syntax-table cperl-st-word)))) + ;; 1+6+2+1+1+2+1=14 extra () before this: + ;; "\\(\\") ;;; (progn @@ -2850,8 +3014,8 @@ the sections using `cperl-pod-head-face', `cperl-pod-face', ;;; (cperl-put-do-not-fontify b (match-beginning 0))) ;;; (t (message "End of format `%s' not found." name)))) ) - (if err (goto-char err) - (message "Scan for pods, formats and here-docs completed."))) + (if (car err-l) (goto-char (car err-l)) + (message "Scan for \"hard\" Perl constructions completed."))) (and (buffer-modified-p) (not modified) (set-buffer-modified-p nil)) @@ -2864,9 +3028,10 @@ the sections using `cperl-pod-head-face', `cperl-pod-face', (skip-chars-backward " \t\n\f" lim) (setq p (point)) (beginning-of-line) - (if (looking-at "^[ \t]*\\(#\\|$\\)") nil ; Only comment, skip + (if (or (looking-at "^[ \t]*\\(#\\|$\\)") + (progn (cperl-to-comment-or-eol) (bolp))) + nil ; Only comment, skip ;; Else - (cperl-to-comment-or-eol) (skip-chars-backward " \t") (if (< p (point)) (goto-char p)) (setq stop t))))) @@ -2931,8 +3096,8 @@ or looks like continuation of the comment on the previous line." (save-excursion (let ((tmp-end (progn (end-of-line) (point))) top done) (save-excursion + (beginning-of-line) (while (null done) - (beginning-of-line) (setq top (point)) (while (= (nth 0 (parse-partial-sexp (point) tmp-end -1)) -1) @@ -3147,6 +3312,7 @@ indentation and initial hashes. Behaves usually outside of comment." (defun imenu-example--create-perl-index (&optional regexp) (require 'cl) + (require 'imenu) ; May be called from TAGS creator (let ((index-alist '()) (index-pack-alist '()) (index-pod-alist '()) (index-unsorted-alist '()) (i-s-f (default-value 'imenu-sort-function)) (index-meth-alist '()) meth @@ -3162,6 +3328,12 @@ indentation and initial hashes. Behaves usually outside of comment." (imenu-progress-message prev-pos) ;;(backward-up-list 1) (cond + ((and ; Skip some noise if building tags + (match-beginning 2) ; package or sub + (eq (char-after (match-beginning 2)) ?p) ; package + (not (save-match-data + (looking-at "[ \t\n]*;")))) ; Plain text word 'package' + nil) ((and (match-beginning 2) ; package or sub ;; Skip if quoted (will not skip multi-line ''-comments :-(): @@ -3473,12 +3645,12 @@ indentation and initial hashes. Behaves usually outside of comment." (2 '(restart 2 nil) nil t))) nil t))) ; local variables, multiple (font-lock-anchored - '("^[ \t]*\\(my\\|local\\)[ \t]*\\(([ \t]*\\)?\\([$@%*][a-zA-Z0-9_:]+\\)" + '("^[ \t{}]*\\(my\\|local\\)[ \t]*\\(([ \t]*\\)?\\([$@%*][a-zA-Z0-9_:]+\\)" (3 font-lock-variable-name-face) ("\\=[ \t]*,[ \t]*\\([$@%*][a-zA-Z0-9_:]+\\)" nil nil (1 font-lock-variable-name-face)))) - (t '("^[ \t]*\\(my\\|local\\)[ \t]*\\(([ \t]*\\)?\\([$@%*][a-zA-Z0-9_:]+\\)" + (t '("^[ \t{}]*\\(my\\|local\\)[ \t]*\\(([ \t]*\\)?\\([$@%*][a-zA-Z0-9_:]+\\)" 3 font-lock-variable-name-face))) '("\\= (point) (marker-position e)) + (/= (current-indentation) c)) + (progn + (beginning-of-line) + (setq s (point)) + (skip-chars-forward " \t") + (delete-region s (point)) + (indent-to-column c))) )) +(defun cperl-make-regexp-x () + (save-excursion + (or cperl-use-syntax-table-text-property + (error "I need to have regex marked!")) + ;; Find the start + (re-search-backward "\\s|") ; Assume it is scanned already. + ;;(forward-char 1) + (let ((b (point)) (e (make-marker)) have-x delim (c (current-column)) + (sub-p (eq (preceding-char) ?s)) s) + (forward-sexp 1) + (set-marker e (1- (point))) + (setq delim (preceding-char)) + (if (and sub-p (eq delim (char-after (- (point) 2)))) + (error "Possible s/blah// - do not know how to deal with")) + (if sub-p (forward-sexp 1)) + (if (looking-at "\\sw*x") + (setq have-x t) + (insert "x")) + ;; Protect fragile " ", "#" + (if have-x nil + (goto-char (1+ b)) + (while (re-search-forward "\\(\\=\\|[^\\\\]\\)\\(\\\\\\\\\\)*[ \t\n#]" e t) ; Need to include (?#) too? + (forward-char -1) + (insert "\\") + (forward-char 1))) + b))) + (defun cperl-beautify-regexp () - "do it. (Experimental, may change semantics, recheck afterwards.) + "do it. (Experimental, may change semantics, recheck the result.) We suppose that the regexp is scanned already." (interactive) - (or cperl-use-syntax-table-text-property - (error "I need to have regex marked!")) - ;; Find the start + (cperl-make-regexp-x) (re-search-backward "\\s|") ; Assume it is scanned already. ;;(forward-char 1) - (let ((b (point)) (e (make-marker)) have-x delim (c (current-column)) - (sub-p (eq (preceding-char) ?s)) s) + (let ((b (point)) (e (make-marker))) (forward-sexp 1) (set-marker e (1- (point))) - (setq delim (preceding-char)) - (if (and sub-p (eq delim (char-after (- (point) 2)))) - (error "Possible s/blah// - do not know how to deal with")) - (if sub-p (forward-sexp 1)) - (if (looking-at "\\sw*x") - (setq have-x t) - (insert "x")) - ;; Protect fragile " ", "#" - (if have-x nil - (goto-char (1+ b)) - (while (re-search-forward "\\(\\=\\|[^\\\\]\\)\\(\\\\\\\\\\)*[ \t\n#]" e t) ; Need to include (?#) too? - (forward-char -1) - (insert "\\") - (forward-char 1))) (cperl-beautify-regexp-piece b e nil))) +(defun cperl-contract-level () + "Find an enclosing group in regexp and contract it. (Experimental, may change semantics, recheck the result.) Unfinished. +We suppose that the regexp is scanned already." + (interactive) + (let ((bb (cperl-make-regexp-x)) done) + (while (not done) + (or (eq (following-char) ?\() + (search-backward "(" (1+ bb) t) + (error "Cannot find `(' which starts a group")) + (setq done + (save-excursion + (skip-chars-backward "\\") + (looking-at "\\(\\\\\\\\\\)*("))) + (or done (forward-char -1))) + (let ((b (point)) (e (make-marker)) s c) + (forward-sexp 1) + (set-marker e (1- (point))) + (goto-char b) + (while (re-search-forward "\\(#\\)\\|\n" e t) + (cond + ((match-beginning 1) ; #-comment + (or c (setq c (current-indentation))) + (beginning-of-line 2) ; Skip + (setq s (point)) + (skip-chars-forward " \t") + (delete-region s (point)) + (indent-to-column c)) + (t + (delete-char -1) + (just-one-space))))))) + +(defun cperl-beautify-level () + "Find an enclosing group in regexp and beautify it. (Experimental, may change semantics, recheck the result.) +We suppose that the regexp is scanned already." + (interactive) + (let ((bb (cperl-make-regexp-x)) done) + (while (not done) + (or (eq (following-char) ?\() + (search-backward "(" (1+ bb) t) + (error "Cannot find `(' which starts a group")) + (setq done + (save-excursion + (skip-chars-backward "\\") + (looking-at "\\(\\\\\\\\\\)*("))) + (or done (forward-char -1))) + (let ((b (point)) (e (make-marker))) + (forward-sexp 1) + (set-marker e (1- (point))) + (cperl-beautify-regexp-piece b e nil)))) + (if (fboundp 'run-with-idle-timer) (progn (defvar cperl-help-shown nil diff --git a/embed.h b/embed.h index 4be72d7..51e5f40 100644 --- a/embed.h +++ b/embed.h @@ -46,6 +46,7 @@ #define av_make Perl_av_make #define av_pop Perl_av_pop #define av_push Perl_av_push +#define av_reify Perl_av_reify #define av_shift Perl_av_shift #define av_store Perl_av_store #define av_undef Perl_av_undef @@ -325,6 +326,7 @@ #define magic_len Perl_magic_len #define magic_nextpack Perl_magic_nextpack #define magic_set Perl_magic_set +#define magic_set_all_env Perl_magic_set_all_env #define magic_setamagic Perl_magic_setamagic #define magic_setarylen Perl_magic_setarylen #define magic_setbm Perl_magic_setbm diff --git a/ext/DynaLoader/DynaLoader.pm b/ext/DynaLoader/DynaLoader.pm index 04404b7..712d575 100644 --- a/ext/DynaLoader/DynaLoader.pm +++ b/ext/DynaLoader/DynaLoader.pm @@ -12,16 +12,21 @@ package DynaLoader; # # Tim.Bunce@ig.co.uk, August 1994 -use vars qw($VERSION); +$VERSION = $VERSION = "1.03"; # avoid typo warning -$VERSION = "1.02"; - -require Carp; require Config; require AutoLoader; *AUTOLOAD = \&AutoLoader::AUTOLOAD; +# The following require can't be removed during maintenance +# releases, sadly, because of the risk of buggy code that does +# require Carp; Carp::croak "..."; without brackets dying +# if Carp hasn't been loaded in earlier compile time. :-( +# We'll let those bugs get found on the development track. +require Carp if $] < 5.00450; + + # enable debug/trace messages from DynaLoader perl code $dl_debug = $ENV{PERL_DL_DEBUG} || 0 unless defined $dl_debug; @@ -82,6 +87,8 @@ if ($dl_debug) { 1; # End of main code +sub croak { require Carp; Carp::croak(@_) } + # The bootstrap function cannot be autoloaded (without complications) # so we define it here: @@ -91,11 +98,14 @@ sub bootstrap { local($module) = $args[0]; local(@dirs, $file); - Carp::confess("Usage: DynaLoader::bootstrap(module)") unless $module; + unless ($module) { + require Carp; + Carp::confess("Usage: DynaLoader::bootstrap(module)"); + } # A common error on platforms which don't support dynamic loading. # Since it's fatal and potentially confusing we give a detailed message. - Carp::croak("Can't load module $module, dynamic loading not available in this perl.\n". + croak("Can't load module $module, dynamic loading not available in this perl.\n". " (You may need to build a new perl executable which either supports\n". " dynamic loading or has the $module module statically linked into it.)\n") unless defined(&dl_load_file); @@ -119,16 +129,17 @@ sub bootstrap { next unless -d $dir; # skip over uninteresting directories # check for common cases to avoid autoload of dl_findfile - last if ($file=_check_file("$dir/$modfname.$dl_dlext")); + my $try = "$dir/$modfname.$dl_dlext"; + last if $file = ($do_expand) ? dl_expandspec($try) : (-f $try && $try); # no luck here, save dir for possible later dl_findfile search - push(@dirs, "-L$dir"); + push @dirs, $dir; } # last resort, let dl_findfile have a go in all known locations - $file = dl_findfile(@dirs, map("-L$_",@INC), $modfname) unless $file; + $file = dl_findfile(map("-L$_",@dirs,@INC), $modfname) unless $file; - Carp::croak("Can't find loadable object for module $module in \@INC (@INC)") - unless $file; + croak("Can't locate loadable object for module $module in \@INC (\@INC contains: @INC)") + unless $file; # wording similar to error from 'require' my $bootname = "boot_$module"; $bootname =~ s/\W/_/g; @@ -153,16 +164,18 @@ sub bootstrap { # it executed. my $libref = dl_load_file($file, $module->dl_load_flags) or - Carp::croak("Can't load '$file' for module $module: ".dl_error()."\n"); + croak("Can't load '$file' for module $module: ".dl_error()."\n"); push(@dl_librefs,$libref); # record loaded object my @unresolved = dl_undef_symbols(); - Carp::carp("Undefined symbols present after loading $file: @unresolved\n") - if @unresolved; + if (@unresolved) { + require Carp; + Carp::carp("Undefined symbols present after loading $file: @unresolved\n"); + } my $boot_symbol_ref = dl_find_symbol($libref, $bootname) or - Carp::croak("Can't find '$bootname' symbol in $file\n"); + croak("Can't find '$bootname' symbol in $file\n"); my $xs = dl_install_xsub("${module}::bootstrap", $boot_symbol_ref, $file); @@ -173,12 +186,12 @@ sub bootstrap { } -sub _check_file { # private utility to handle dl_expandspec vs -f tests - my($file) = @_; - return $file if (!$do_expand && -f $file); # the common case - return $file if ( $do_expand && ($file=dl_expandspec($file))); - return undef; -} +#sub _check_file { # private utility to handle dl_expandspec vs -f tests +# my($file) = @_; +# return $file if (!$do_expand && -f $file); # the common case +# return $file if ( $do_expand && ($file=dl_expandspec($file))); +# return undef; +#} # Let autosplit and the autoloader deal with these functions: @@ -243,7 +256,8 @@ sub dl_findfile { foreach $name (@names) { my($file) = "$dir/$name"; print STDERR " checking in $dir for $name\n" if $dl_debug; - $file = _check_file($file); + $file = ($do_expand) ? dl_expandspec($file) : (-f $file && $file); + #$file = _check_file($file); if ($file) { push(@found, $file); next arg; # no need to look any further @@ -279,6 +293,7 @@ sub dl_expandspec { my $file = $spec; # default output to input if ($Is_VMS) { # dl_expandspec should be defined in dl_vms.xs + require Carp; Carp::croak("dl_expandspec: should be defined in XS file!\n"); } else { return undef unless -f $file; diff --git a/ext/IO/lib/IO/Socket.pm b/ext/IO/lib/IO/Socket.pm index ab19170..aadb502 100644 --- a/ext/IO/lib/IO/Socket.pm +++ b/ext/IO/lib/IO/Socket.pm @@ -39,6 +39,11 @@ C only looks for one key C which tells new which domain the socket will be in. All other arguments will be passed to the configuration method of the package for that domain, See below. +Cs will be in autoflush mode after creation. Note that +versions of IO::Socket prior to 1.1603 (as shipped with Perl 5.004_04) +did not do this. So if you need backward compatibility, you should +set autoflush explicitly. + =back =head1 METHODS @@ -118,7 +123,7 @@ use Exporter; @ISA = qw(IO::Handle); -$VERSION = "1.1602"; +$VERSION = "1.1603"; sub import { my $pkg = shift; @@ -129,6 +134,7 @@ sub import { sub new { my($class,%arg) = @_; my $fh = $class->SUPER::new(); + $fh->autoflush; ${*$fh}{'io_socket_timeout'} = delete $arg{Timeout}; @@ -392,7 +398,7 @@ and some related methods. The constructor can take the following options PeerPort Remote port or service [()] | LocalAddr Local host bind address hostname[:port] LocalPort Local host bind port [()] | - Proto Protocol name "tcp" | "udp" | ... + Proto Protocol name (or number) "tcp" | "udp" | ... Type Socket type SOCK_STREAM | SOCK_DGRAM | ... Listen Queue size for listen Reuse Set SO_REUSEADDR before binding @@ -410,10 +416,13 @@ parenthesis which is used if the service is not known by the system. The C specification can also be embedded in the C by preceding it with a ":". -Only one of C or C needs to be specified, one will be -assumed from the other. If you specify a symbolic C port, -then the constructor will try to derive C and C from -the service name. +If C is not given and you specify a symbolic C port, +then the constructor will try to derive C from the service +name. As a last resort C "tcp" is assumed. The C +parameter will be deduced from C if not specified. + +If the constructor is only passed a single argument, it is assumed to +be a C specification. Examples: @@ -428,6 +437,9 @@ Examples: LocalPort => 9000, Proto => 'tcp'); + $sock = IO::Socket::INET->new('127.0.0.1:25'); + + =head2 METHODS =over 4 @@ -463,6 +475,13 @@ peer host in a text form xx.xx.xx.xx =cut +sub new +{ + my $class = shift; + unshift(@_, "PeerAddr") if @_ == 1; + return $class->SUPER::new(@_); +} + sub _sock_info { my($addr,$port,$proto) = @_; my @proto = (); @@ -535,6 +554,7 @@ sub configure { unless(defined $raddr); } + $proto ||= (getprotobyname "tcp")[2]; return _error($fh,'Cannot determine protocol') unless($proto); diff --git a/ext/util/extliblist b/ext/util/extliblist deleted file mode 100755 index 2351ddf..0000000 --- a/ext/util/extliblist +++ /dev/null @@ -1,155 +0,0 @@ -case $CONFIG in -'') - if test -f config.sh; then TOP=.; - elif test -f ../config.sh; then TOP=..; - elif test -f ../../config.sh; then TOP=../..; - elif test -f ../../../config.sh; then TOP=../../..; - elif test -f ../../../../config.sh; then TOP=../../../..; - else - echo "Can't find config.sh."; exit 1 - fi - . $TOP/config.sh - ;; -esac -: extliblist -: -: Author: Andy Dougherty doughera@lafcol.lafayette.edu -: -: This utility was only used by the old Makefile.SH extension -: mechanism. It is now obsolete and may be removed in a future -: release. -: -: This utility takes a list of libraries in the form -: -llib1 -llib2 -llib3 -: and prints out lines suitable for inclusion in an extension -: Makefile. -: Extra library paths may be included with the form -L/another/path -: this will affect the searches for all subsequent libraries. -: -: It is intended to be "dotted" from within an extension Makefile.SH. -: see ext/POSIX/Makefile.SH for an example. -: Prior to calling this, the variable potential_libs should be set -: to the potential list of libraries -: -: It sets the following -: extralibs = full list of libraries needed for static linking. -: Only those libraries that actually exist are included. -: dynaloadlibs = full path names of those libraries that are needed -: but can be linked in dynamically on this platform. On -: SunOS, for example, this would be .so* libraries, -: but not archive libraries. -: Eventually, this list can be used to write a bootstrap file. -: statloadlibs = list of those libraries which must be statically -: linked into the shared library. On SunOS 4.1.3, -: for example, I have only an archive version of -: -lm, and it must be linked in statically. -: -: This script uses config.sh variables libs, libpth, and so. It is mostly -: taken from the metaconfig libs.U unit. -extralibs='' -dynaloadlibs='' -statloadlibs='' -Llibpth='' -for thislib in `echo "XXX $potential_libs " | $sed 's/ -l/ /g'` ; do - case "$thislib" in - XXX) - : Handle case where potential_libs is empty. - ;; - -L*) - : Handle possible linker path arguments. - newpath=`echo $thislib | $sed 's/^-L//'` - if $test -d $newpath; then - Llibpth="$Llibpth $newpath" - extralibs="$extralibs $thislib" - statloadlibs="$statloadlibs $thislib" - fi - ;; - *) - : Handle possible library arguments. - for thispth in $Llibpth $libpth; do - : Loop over possible wildcards and take the last one. - for fullname in $thispth/lib$thislib.$so.[0-9]* ; do - : - done - if $test -f $fullname; then - break - elif fullname=$thispth/lib$thislib.$so && $test -f $fullname; then - break - elif fullname=$thispth/lib${thislib}_s.a && $test -f $fullname; then - thislib=${thislib}_s - break - elif fullname=$thispth/lib${thislib}.a && $test -f $fullname; then - break - elif fullname=$thispth/Slib${thislib}.a && $test -f $fullname; then - break - else - fullname='' - fi - done - : Now update library lists - case "$fullname" in - '') - : Skip nonexistent files - ;; - *) - : Do not add it into the extralibs if it is already linked in - : with the main perl executable. - case " $libs " in - *" -l$thislib "*|*" -l${thislib}_s "*) ;; - *) extralibs="$extralibs -l$thislib" ;; - esac - : - : For NeXT and DLD, put files into DYNALOADLIBS to be - : converted into a boostrap file. For other systems, - : we will use ld with what I have misnamed STATLOADLIBS - : to assemble the shared object. - case "$dlsrc" in - dl_dld*|dl_next*) - dynaloadlibs="$dynaloadlibs $fullname" ;; - *) - case "$fullname" in - *.a) - statloadlibs="$statloadlibs -l$thislib" - ;; - *) - : For SunOS4, do not add in this shared library - : if it is already linked in the main - : perl executable - case "$osname" in - sunos) - case " $libs " in - *" -l$thislib "*) ;; - *) statloadlibs="$statloadlibs -l$thislib" ;; - esac - ;; - *) - statloadlibs="$statloadlibs -l$thislib" - ;; - esac - ;; - esac - ;; - esac - ;; - esac - ;; - esac -done - -case "$dlsrc" in -dl_next*) - extralibs=`echo " $extralibs "| $sed -e 's/ -lm / /'` ;; -esac - -set X $extralibs -shift -extralibs="$*" - -set X $dynaloadlibs -shift -dynaloadlibs="$*" - -set X $statloadlibs -shift -statloadlibs="$*" - diff --git a/ext/util/make_ext b/ext/util/make_ext index bfbcc83..70a5d2e 100644 --- a/ext/util/make_ext +++ b/ext/util/make_ext @@ -4,16 +4,35 @@ # It primarily used by the perl Makefile: # # d_dummy $(dynamic_ext): miniperl preplibrary FORCE -# ext/util/make_ext dynamic $@ +# @sh ext/util/make_ext dynamic $@ MAKE=$(MAKE) LIBPERL_A=$(LIBPERL) # # It may be deleted in a later release of perl so try to # avoid using it for other purposes. target=$1; shift extspec=$1; shift +makecmd=$1; shift # Should be something like MAKE=make passthru="$*" # allow extra macro=value to be passed through echo "" +# Previously, $make was taken from config.sh. However, the user might +# instead be running a possibly incompatible make. This might happen if +# the user types "gmake" instead of a plain "make", for example. The +# correct current value of MAKE will come through from the main perl +# makefile as MAKE=/whatever/make in $makecmd. We'll be cautious in +# case third party users of this script (are there any?) don't have the +# MAKE=$(MAKE) argument, which was added after 5.004_03. +case "$makecmd" in +MAKE=*) + eval $makecmd + ;; +*) echo 'ext/util/make_ext: WARNING: Please include MAKE=$(MAKE)' + echo ' in your call to make_ext. See ext/util/make_ext for details.' + exit 1 + ;; +esac + + case $CONFIG in '') if test -f config.sh; then TOP=.; @@ -107,10 +126,10 @@ clean) ;; realclean) ;; *) # Give makefile an opportunity to rewrite itself. # reassure users that life goes on... - $make config $passthru || echo "$make config failed, continuing anyway..." + $MAKE config $passthru || echo "$MAKE config failed, continuing anyway..." ;; esac -$make $makeopts $target $makeargs $passthru || exit +$MAKE $makeopts $target $makeargs $passthru || exit exit $? diff --git a/global.sym b/global.sym index a8d99d7..864be81 100644 --- a/global.sym +++ b/global.sym @@ -310,6 +310,7 @@ av_len av_make av_pop av_push +av_reify av_shift av_store av_undef @@ -530,6 +531,7 @@ magic_setsubstr magic_settaint magic_setuvar magic_setvec +magic_set_all_env magic_wipepack magicname markstack_grow diff --git a/gv.c b/gv.c index 6658259..fff3bcf 100644 --- a/gv.c +++ b/gv.c @@ -170,8 +170,8 @@ I32 level; gvp = (GV**)hv_fetch(stash, "ISA", 3, FALSE); av = (gvp && (gv = *gvp) && gv != (GV*)&sv_undef) ? GvAV(gv) : Nullav; - /* create @.*::SUPER::ISA on demand */ - if (!av) { + /* create and re-create @.*::SUPER::ISA on demand */ + if (!av || !SvMAGIC(av)) { char* packname = HvNAME(stash); STRLEN packlen = strlen(packname); @@ -740,6 +740,7 @@ I32 sv_type; case '7': case '8': case '9': + case '\023': ro_magicalize: SvREADONLY_on(GvSV(gv)); magicalize: diff --git a/hints/bsdos.sh b/hints/bsdos.sh index ef98ace..53adfa3 100644 --- a/hints/bsdos.sh +++ b/hints/bsdos.sh @@ -1,39 +1,60 @@ # hints/bsdos.sh # -# hints file for BSD/OS 2.x (adapted from bsd386.sh) -# Original by Neil Bowers -# Tue Oct 4 12:01:34 EDT 1994 -# Updated by Tony Sanders -# Mon Nov 27 17:25:51 CST 1995 +# hints file for BSD/OS (adapted from bsd386.sh) +# Original by Neil Bowers ; Tue Oct 4 12:01:34 EDT 1994 +# Updated by Tony Sanders ; Sat Aug 23 12:47:45 MDT 1997 +# Added 3.1 with ELF dynamic libraries +# SYSV IPC tested Ok so I re-enabled. # -# You can override the compiler and loader on the Configure command line: -# ./Configure -Dcc=shlicc2 -Dld=shlicc2 - -# filename extension for shared library objects -so='o' +# To override the compiler on the command line: +# ./Configure -Dcc=gcc2 +# +# The BSD/OS distribution is built with: +# ./Configure -des -Dbsdos_distribution=defined -# Don't use this for Perl 5.002, which needs parallel sig_name and sig_num lists -#sig_name='ZERO HUP INT QUIT ILL TRAP IOT EMT FPE KILL BUS SEGV SYS PIPE ALRM TERM URG STOP TSTP CONT CHLD TTIN TTOU IO XCPU XFSZ VTALRM PROF WINCH INFO USR1 USR2 ' signal_t='void' d_voidsig='define' +usemymalloc='n' + +# setre?[ug]id() have been replaced by the _POSIX_SAVED_IDS versions. +# See http://www.bsdi.com/bsdi-man?setuid(2) +d_setregid='undef' +d_setreuid='undef' +d_setrgid='undef' +d_setruid='undef' + # we don't want to use -lnm, since exp() is busted (in 1.1 anyway) set `echo X "$libswanted "| sed -e 's/ nm / /'` shift libswanted="$*" -# BSD/OS X libraries are in their own tree +# X libraries are in their own tree glibpth="$glibpth /usr/X11/lib" ldflags="$ldflags -L/usr/X11/lib" # Avoid telldir prototype conflict in pp_sys.c pp_sys_cflags='ccflags="$ccflags -DHAS_TELLDIR_PROTOTYPE"' +case "$optimize" in +'') optimize='-O2' ;; +esac + case "$bsdos_distribution" in -defined) - d_portable='no' +''|undef|false) ;; +*) + d_dosuid='define' + d_portable='undef' prefix='/usr/contrib' + perlpath='/usr/bin/perl5' + startperl='#!/usr/bin/perl5' + scriptdir='/usr/contrib/bin' + privlib='/usr/libdata/perl5' + man1dir='/usr/contrib/man/man1' man3dir='/usr/contrib/man/man3' + # phlib added by BSDI -- we share the *.ph include dir with perl4 + phlib="/usr/libdata/perl5/site_perl/$(arch)-$osname/include" + phlibexp="/usr/libdata/perl5/site_perl/$(arch)-$osname/include" ;; esac @@ -48,120 +69,41 @@ case "$osvers" in '') cc='gcc2' ;; esac ;; -2.0*) - # default to GCC 2.X w/shared libraries - case "$cc" in - '') cc='shlicc2' ;; - esac - - # default ld to shared library linker - case "$ld" in - '') ld='shlicc2' ;; - esac - - # setre?[ug]id() have been replaced by the _POSIX_SAVED_IDS stuff - # in 4.4BSD-based systems (including BSD/OS 2.0 and later). - # See http://www.bsdi.com/bsdi-man?setuid(2) - d_setregid='undef' - d_setreuid='undef' - d_setrgid='undef' - d_setruid='undef' - ;; -2.1*) - # Use 2.1's shlicc2 for dynamic linking - # Since cc -o is linking, use it for compiling too. - # I'm not sure whether Configure is careful about - # distinguishing between the two. +2.0*|2.1*|3.0*) + so='o' + # default to GCC 2.X w/shared libraries case "$cc" in '') cc='shlicc2' cccdlflags=' ' ;; # Avoid the dreaded -fpic esac - # Link with shared libraries in 2.1 - # Turns out that shlicc2 will automatically use the - # shared libs, so don't explicitly specify -lc_s.2.1.* + # default ld to shared library linker case "$ld" in '') ld='shlicc2' lddlflags='-r' ;; # this one is necessary esac - # setre?[ug]id() have been replaced by the _POSIX_SAVED_IDS stuff - # in 4.4BSD-based systems (including BSD/OS 2.0 and later). - # See http://www.bsdi.com/bsdi-man?setuid(2) - # This stuff may or may not be right, but it works. - d_setregid='undef' - d_setreuid='undef' - d_setrgid='undef' - d_setruid='undef' - - # based on the 5.001m hints file from BSD/OS source disk - # (this is needed for pTk to work) - - # BSD/OS 2.1 doesn't (yet) support true dynamic linking. - # So we "preload' the shared libraries by linking against - # them, even though we don't pull in any symbols thereby. + # Must preload the static shared libraries. libswanted="Xpm Xaw Xmu Xt SM ICE Xext X11 $libswanted" libswanted="rpc curses termcap $libswanted" - ;; -3.0*) - # adapted from 2.1 entry by Christopher Davis +# +# * libnet on Digital UNIX is for JAVA, not for sockets. +# +# # perl5.003_28: # # 22-Feb-1997 Jarkko Hietaniemi diff --git a/hints/dynixptx.sh b/hints/dynixptx.sh index 55824f6..78a45e4 100644 --- a/hints/dynixptx.sh +++ b/hints/dynixptx.sh @@ -15,3 +15,10 @@ libswanted=`echo $libswanted | sed -e 's/ inet / /'` # Configure defaults to usenm='y', which doesn't work very well usenm='n' +# Reported by bruce@aps.org ("Bruce P. Schuck") as needed for +# DYNIX/ptx 4.0 V4.2.1 to get socket i/o to work +# Not defined by default in case they break other versions. +# These probably need to be worked into a piece of code that +# checks for the need for this setting. +# cppflags='-Wc,+abi-socket -I/usr/local/include' +# ccflags='-Wc,+abi-socket -I/usr/local/include' diff --git a/hints/irix_6.sh b/hints/irix_6.sh index 060d972..795b6ab 100644 --- a/hints/irix_6.sh +++ b/hints/irix_6.sh @@ -63,6 +63,10 @@ case "$cc" in ld=ld ldflags=' -L/usr/local/lib -L/usr/lib32 -L/lib32' cccdlflags=' ' + # From: David Billinghurst + # If you get complaints about so_locations then change the following + # line to something like: + # lddlflags="-n32 -shared -check_registry /usr/lib32/so_locations" lddlflags="-n32 -shared" libc='/usr/lib32/libc.so' plibpth='/usr/lib32 /lib32 /usr/ccs/lib' diff --git a/hints/linux.sh b/hints/linux.sh index 6a11a42..8ddb765 100644 --- a/hints/linux.sh +++ b/hints/linux.sh @@ -29,6 +29,14 @@ esac # gcc-2.6.3 defines _G_HAVE_BOOL to 1, but doesn't actually supply bool. ccflags="-Dbool=char -DHAS_BOOL $ccflags" +# libc6, aka glibc2, seems to need STRUCT_TM_HASZONE defined. +# Thanks to Bart Schuller +# See Message-ID: <19971009002636.50729@tanglefoot> +# This is currently commented out for maintenance releases +# but should probably be uncommented for 5.005 or after +# more widespread testing. +#POSIX_cflags='ccflags="$ccflags -DSTRUCT_TM_HASZONE"' + # BSD compatability library no longer needed set `echo X "$libswanted "| sed -e 's/ bsd / /'` shift diff --git a/hints/machten.sh b/hints/machten.sh index 55feadc..380f702 100644 --- a/hints/machten.sh +++ b/hints/machten.sh @@ -1,8 +1,8 @@ # machten.sh -# This is for MachTen 4.0.3. It might work on other versions too. +# This is for MachTen 4.0.3. It might work on other versions and variants too. # -# MachTen users might need a fixed tr from ftp.tenon.com. This should -# be described in the MachTen release notes. +# Users of earlier MachTen versions might need a fixed tr from ftp.tenon.com. +# This should be described in the MachTen release notes. # # MachTen 2.x has its own hint file. # @@ -13,6 +13,7 @@ # Martijn Koster # Richard Yeh # +# Raise perl's stack size -- Dominic Dunlop 970922 # Reinstate sigsetjmp iff version is 4.0.3 or greater; use nm # (assumes Configure change); prune libswanted -- Dominic Dunlop 970113 # Warn about test failure due to old Berkeley db -- Dominic Dunlop 970105 @@ -24,9 +25,6 @@ # # MachTen 4.X does support dynamic loading, but perl doesn't # know how to use it yet. -# -# Updated by Dominic Dunlop -# Tue Jan 14 10:17:18 WET 1997 # Power MachTen is a real memory system and its standard malloc # has been optimized for this. Using this malloc instead of Perl's @@ -36,6 +34,11 @@ usemymalloc='false' # Make symbol table listings les voluminous nmopts=-gp +# Increase perl's stack size. Without this, lib/complex.t crashes out. +# Particularly perverse programs may require that perl has an even larger +# stack allocation than that specified here. (See man setstackspace ) +ldflags='-Xlstack=0x014000' + # Install in /usr/local by default prefix='/usr/local' diff --git a/hints/os2.sh b/hints/os2.sh index b468f2d..2a589b5 100644 --- a/hints/os2.sh +++ b/hints/os2.sh @@ -6,14 +6,11 @@ # Trimmed and comments added by # Andy Dougherty # Exactly what is required beyond a standard OS/2 installation? -# There are notes about "patched pdksh" I do not understand. +# (see in README.os2) # Note that symbol extraction code gives wrong answers (sometimes?) on # gethostent and setsid. -# Note that during the .obj compile you need to move the perl.dll file -# to LIBPATH :-( - # Optimization (GNU make 3.74 cannot be loaded :-(): emxload -m 30 sh.exe ls.exe tr.exe id.exe sed.exe # make.exe emxload -m 30 grep.exe egrep.exe fgrep.exe cat.exe rm.exe mv.exe cp.exe @@ -24,28 +21,59 @@ path_sep=\; if test -f $sh.exe; then sh=$sh.exe; fi startsh="#!$sh" - -sysman=`../UU/loc . /man/man1 c:/man/man1 c:/usr/man/man1 d:/man/man1 d:/usr/man/man1 e:/man/man1 e:/usr/man/man1 f:/man/man1 f:/usr/man/man1 g:/man/man1 g:/usr/man/man1 /usr/man/man1` cc='gcc' -usrinc='/emx/include' -emxpath="`../UU/loc . /emx c:/emx d:/emx e:/emx f:/emx g:/emx h:/emx /emx`" -libemx="$emxpath/lib" +# Get some standard things (indented to avoid putting in config.sh): + oifs="$IFS" + IFS=" ;" + set $MANPATH + tryman="$@" + set $LIBRARY_PATH + libemx="$@" + set $C_INCLUDE_PATH + usrinc="$@" + IFS="$oifs" + tryman="`../UU/loc . /man $tryman`" + tryman="`echo $tryman | tr '\\\' '/'`" + + # indented to avoid having it *two* times at start + libemx="`../UU/loc os2.a /emx/lib $libemx`" + +usrinc="`../UU/loc stdlib.h /emx/include $usrinc`" +usrinc="`dirname $usrinc | tr '\\\' '/'`" +libemx="`dirname $libemx | tr '\\\' '/'`" + +if test -d $tryman/man1; then + sysman="$tryman/man1" +else + sysman="`../UU/loc . /man/man1 c:/man/man1 c:/usr/man/man1 d:/man/man1 d:/usr/man/man1 e:/man/man1 e:/usr/man/man1 f:/man/man1 f:/usr/man/man1 g:/man/man1 g:/usr/man/man1 /usr/man/man1`" +fi + +emxpath="`dirname $libemx`" +if test ! -d "$emxpath"; then + emxpath="`../UU/loc . /emx c:/emx d:/emx e:/emx f:/emx g:/emx h:/emx /emx`" +fi + +if test ! -d "$libemx"; then + libemx="$emxpath/lib" +fi if test ! -d "$libemx"; then if test -d "$LIBRARY_PATH"; then - usrinc="$LIBRARY_PATH" + libemx="$LIBRARY_PATH" else libemx="`../UU/loc . X c:/emx/lib d:/emx/lib e:/emx/lib f:/emx/lib g:/emx/lib h:/emx/lib /emx/lib`" fi fi -if test -d "$emxpath/include"; then - usrinc="$emxpath/include" -else - if test -d "$C_INCLUDE_PATH"; then - usrinc="$C_INCLUDE_PATH" +if test ! -d "$usrinc"; then + if test -d "$emxpath/include"; then + usrinc="$emxpath/include" else - usrinc="`../UU/loc . X c:/emx/include d:/emx/include e:/emx/include f:/emx/include g:/emx/include h:/emx/include /emx/include`" + if test -d "$C_INCLUDE_PATH"; then + usrinc="$C_INCLUDE_PATH" + else + usrinc="`../UU/loc . X c:/emx/include d:/emx/include e:/emx/include f:/emx/include g:/emx/include h:/emx/include /emx/include`" + fi fi fi diff --git a/hints/os390.sh b/hints/os390.sh new file mode 100644 index 0000000..fd590ea --- /dev/null +++ b/hints/os390.sh @@ -0,0 +1,33 @@ +# hints/os390.sh +# OS/390 OpenEdition Release 3 Mon Sep 22 1997 thanks to: +# +# John Pfuntner +# Len Johnson +# Bud Huff +# Peter Prymmer +# Andy Dougherty +# Tim Bunce +# +# as well as the authors of the aix.sh file +# + +cc='c89' +ccflags='-DMAXSIG=38 -DOEMVS -D_OE_SOCKETS -D_XOPEN_SOURCE_EXTENDED -D_ALL_SOURCE' +optimize='none' +alignbytes=8 +usemymalloc='y' +so='a' +dlext='none' +d_shmatprototype='define' +usenm='false' +i_time='define' +i_systime='define' +d_select='undef' + +# (from aix.sh) +# uname -m output is too specific and not appropriate here +# +case "$archname" in +'') archname="$osname" ;; +esac + diff --git a/hints/qnx.sh b/hints/qnx.sh index 9334c94..947c98f 100644 --- a/hints/qnx.sh +++ b/hints/qnx.sh @@ -1,10 +1,10 @@ #---------------------------------------------------------------- # QNX hints # -# As of perl5.003_09, perl5 will compile without errors -# and pass almost all the tests in the test suite. The remaining -# failures have been identified as bugs in the Watcom libraries -# which I hope will be fixed in the near future. +# As of perl5.004_04, all tests pass under: +# QNX 4.23A +# Watcom 10.6 with Beta/970211.wcc.update.tar.F +# socket3r.lib Nov21 1996. # # As with many unix ports, this one depends on a few "standard" # unix utilities which are not necessarily standard for QNX. @@ -33,13 +33,16 @@ #---------------------------------------------------------------- # Outstanding Issues: # lib/posix.t test fails on test 17 because acos(1) != 0. -# Watcom promises to fix this in next release. +# Resolved in 970211 Beta # lib/io_udp.t test hangs because of a bug in getsockname(). # Fixed in latest BETA socket3r.lib # If there is a softlink in your path, Findbin will fail. -# This is a documented feature of getpwd(). +# This is a documented feature of perl's getpwd(). # There is currently no support for dynamically linked # libraries. +# op/magic.t failure due to a feature of QNX which rewrites script +# names before they are executed. I think you'll find that if +# you cd `fullpath -t` before doing the make, the test will pass. #---------------------------------------------------------------- # At present, all QNX systems are equivalent architectures, # so it might be reasonable to call archname=qnx rather than @@ -54,6 +57,10 @@ # If you have suggestions or changes, please let me know. #---------------------------------------------------------------- +echo "" +echo "Some tests may fail. Please read the hints/qnx.sh file." +echo "" + #---------------------------------------------------------------- # QNX doesn't come with a csh and the ports of tcsh I've used # don't work reliably: @@ -63,6 +70,16 @@ d_csh='undef' full_csh='' #---------------------------------------------------------------- +# setuid scripts are secure under QNX. +# (Basically, the same race conditions apply, but assuming +# the scripts are located in a secure directory, the methods +# for exploiting the race condition are defeated because +# the loader expands the script name fully before executing +# the interpreter.) +#---------------------------------------------------------------- +d_suidsafe='define' + +#---------------------------------------------------------------- # difftime is implemented as a preprocessor macro, so it doesn't show # up in the libraries: #---------------------------------------------------------------- @@ -74,16 +91,6 @@ d_difftime='define' #---------------------------------------------------------------- d_strtod='define' -#---------------------------------------------------------------- -# The following exist in the libraries, but there are no -# prototypes available: -#---------------------------------------------------------------- -d_setregid='undef' -d_setreuid='undef' -d_setlinebuf='undef' -d_truncate='undef' -d_getpgid='undef' - lib_ext='3r.lib' libc='/usr/lib/clib3r.lib' @@ -107,7 +114,7 @@ ccflags='-DHIDEMYMALLOC -mf -w4 -Wc,-wcd=202 -Wc,-wcd=203 -Wc,-wcd=302 -Wc,-fi=u # link as well as the compile. If optimize != -g, you should # remove this. #---------------------------------------------------------------- -ldflags="-g" +ldflags="-g -N1M" so='none' selecttype='fd_set *' @@ -144,6 +151,7 @@ if [ -z "`which nm 2>/dev/null`" ]; then #%C [ ...] # Designed to mimic Unix's nm utility to list # defined symbols in a library + unset WLIB for i in $*; do wlib $i; done | awk ' /^ / { diff --git a/hv.c b/hv.c index f63dff8..4eaae0f 100644 --- a/hv.c +++ b/hv.c @@ -886,7 +886,7 @@ HV *hv; } xhv->xhv_riter = -1; xhv->xhv_eiter = Null(HE*); - return xhv->xhv_fill; + return xhv->xhv_fill; /* should be xhv->xhv_keys? May change later */ } HE * @@ -962,7 +962,10 @@ register HE *entry; I32 *retlen; { if (HeKLEN(entry) == HEf_SVKEY) { - return SvPV(HeKEY_sv(entry), *(STRLEN*)retlen); + STRLEN len; + char *p = SvPV(HeKEY_sv(entry), len); + *retlen = len; + return p; } else { *retlen = HeKLEN(entry); diff --git a/installperl b/installperl index 9686bfb..e999d3b 100755 --- a/installperl +++ b/installperl @@ -128,9 +128,9 @@ push(@corefiles,'perl.exp') if $^O eq 'aix'; push(@corefiles,'sperl.o') if -f 'sperl.o'; foreach $file (@corefiles) { # HP-UX (at least) needs to maintain execute permissions - # on dynamically-loaded libraries. + # on dynamically-loadable libraries. So we do it for all. copy_if_diff($file,"$installarchlib/CORE/$file") - and chmod($file =~ /^\.(so|$dlext)$/ ? 0555 : 0444, + and chmod($file =~ /\.(so|\Q$dlext\E)$/ ? 0555 : 0444, "$installarchlib/CORE/$file"); } @@ -401,6 +401,11 @@ sub installlib { local($depth) = $dir ? "lib/$dir" : "lib"; my $name = $_; + + if ($name eq 'CVS' && -d $name) { + $File::Find::prune = 1; + return; + } # ignore patch backups and the .exists files. return if $name =~ m{\.orig$|~$|^\.exists}; diff --git a/lib/AutoLoader.pm b/lib/AutoLoader.pm index c45483b..2773a90 100644 --- a/lib/AutoLoader.pm +++ b/lib/AutoLoader.pm @@ -1,6 +1,5 @@ package AutoLoader; -use Carp; use vars qw(@EXPORT @EXPORT_OK); BEGIN { @@ -42,7 +41,9 @@ AUTOLOAD { } if ($@){ $@ =~ s/ at .*\n//; - croak $@; + my $error = $@; + require Carp; + Carp::croak($error); } } } @@ -83,7 +84,11 @@ sub import { $path ="auto/$calldir/autosplit.ix"; eval { require $path; }; } - carp $@ if ($@); + if ($@) { + my $error = $@; + require Carp; + Carp::carp($error); + } } } @@ -169,6 +174,7 @@ Instead, they should define their own AUTOLOAD subroutines along these lines: use AutoLoader; + use Carp; sub AUTOLOAD { my $constname; @@ -183,7 +189,7 @@ lines: croak "Your vendor has not defined constant $constname"; } } - eval "sub $AUTOLOAD { $val }"; + *$AUTOLOAD = sub { $val }; # same as: eval "sub $AUTOLOAD { $val }"; goto &$AUTOLOAD; } diff --git a/lib/CPAN.pm b/lib/CPAN.pm index 8271076..11af0a6 100644 --- a/lib/CPAN.pm +++ b/lib/CPAN.pm @@ -1,12 +1,17 @@ package CPAN; -use vars qw{$Try_autoload - $META $Signal $Cwd $End $Suppress_readline %Dontload}; +use vars qw{$Try_autoload $Revision + $META $Signal $Cwd $End + $Suppress_readline %Dontload + $Frontend + }; -$VERSION = '1.27'; +$VERSION = '1.3102'; -# $Id: CPAN.pm,v 1.160 1997/07/28 12:21:56 k Exp $ +# $Id: CPAN.pm,v 1.202 1997/09/23 18:30:36 k Exp k $ -# my $version = substr q$Revision: 1.160 $, 10; # only used during development +# only used during development: +$Revision = ""; +# $Revision = "[".substr(q$Revision: 1.202 $, 10)."]"; use Carp (); use Config (); @@ -43,14 +48,19 @@ END { $End++; &cleanup; } $CPAN::DEBUG ||= 0; $CPAN::Signal ||= 0; +$CPAN::Frontend ||= "CPAN::Shell"; package CPAN; use vars qw($VERSION @EXPORT $AUTOLOAD $DEBUG $META $term); use strict qw(vars); -@CPAN::ISA = qw(CPAN::Debug Exporter MM); # the MM class from - # MakeMaker, gives us - # catfile and catdir +@CPAN::ISA = qw(CPAN::Debug Exporter MM); # MM will go away + # soonish. Already version + # 1.29 doesn't rely on + # catfile and catdir being + # available via + # inheritance. Anything else + # in danger? @EXPORT = qw( autobundle bundle expand force get @@ -69,14 +79,12 @@ sub AUTOLOAD { my $ok = CPAN::Shell->try_dot_al($AUTOLOAD); if ($ok) { goto &$AUTOLOAD; - } else { - warn "not OK: $@"; +# } else { +# $CPAN::Frontend->mywarn("Could not autoload $AUTOLOAD"); } - warn "CPAN doesn't know how to autoload $AUTOLOAD :-( -Nothing Done. -"; - sleep 1; - CPAN::Shell->h; + $CPAN::Frontend->mywarn(qq{Unknown command "$AUTOLOAD". }. + qq{Type ? for help. +}); } } @@ -103,11 +111,13 @@ sub shell { ($term->ReadLine ne "Term::ReadLine::Stub") ? "enabled" : "available (try ``install Bundle::CPAN'')"; - print qq{ -cpan shell -- CPAN exploration and modules installation (v$CPAN::VERSION) -Readline support $rl_avail + $CPAN::Frontend->myprint( + qq{ +cpan shell -- CPAN exploration and modules installation (v$CPAN::VERSION$CPAN::Revision) +ReadLine support $rl_avail -} unless $CPAN::Config->{'inhibit_startup_message'} ; +}) unless $CPAN::Config->{'inhibit_startup_message'} ; + my($continuation) = ""; while () { if ($Suppress_readline) { print $prompt; @@ -116,10 +126,17 @@ Readline support $rl_avail } else { last unless defined ($_ = $term->readline($prompt)); } + $_ = "$continuation$_" if $continuation; s/^\s+//; next if /^$/; $_ = 'h' if $_ eq '?'; - if (/^\!/) { + if (/^q(?:uit)?$/i) { + last; + } elsif (s/\\$//s) { + chomp; + $continuation = $_; + $prompt = " > "; + } elsif (/^\!/) { s/^\!//; my($eval) = $_; package CPAN::Eval; @@ -128,8 +145,8 @@ Readline support $rl_avail CPAN->debug("eval[$eval]") if $CPAN::DEBUG; eval($eval); warn $@ if $@; - } elsif (/^q(?:uit)?$/i) { - last; + $continuation = ""; + $prompt = "cpan> "; } elsif (/./) { my(@line); if ($] < 5.00322) { # parsewords had a bug until recently @@ -142,17 +159,19 @@ Readline support $rl_avail my $command = shift @line; eval { CPAN::Shell->$command(@line) }; warn $@ if $@; + chdir $cwd; + $CPAN::Frontend->myprint("\n"); + $continuation = ""; + $prompt = "cpan> "; } } continue { - &cleanup, die "Goodbye\n" if $Signal; - chdir $cwd; - print "\n"; + &cleanup, $CPAN::Frontend->mydie("Goodbye\n") if $Signal; } } package CPAN::CacheMgr; use vars qw($Du); -@CPAN::CacheMgr::ISA = qw(CPAN::InfoObj); +@CPAN::CacheMgr::ISA = qw(CPAN::InfoObj CPAN); use File::Find; package CPAN::Config; @@ -166,7 +185,7 @@ use vars qw(%can $dot_cpan); ); package CPAN::FTP; -use vars qw($Ua); +use vars qw($Ua $Thesite $Themethod); @CPAN::FTP::ISA = qw(CPAN::Debug); package CPAN::Complete; @@ -200,30 +219,29 @@ use vars qw($AUTOLOAD $redef @ISA); #-> sub CPAN::Shell::AUTOLOAD ; sub AUTOLOAD { my($autoload) = $AUTOLOAD; + my $class = shift(@_); $autoload =~ s/.*:://; if ($autoload =~ /^w/) { if ($CPAN::META->has_inst('CPAN::WAIT')) { - CPAN::WAIT->wh; + CPAN::WAIT->$autoload(@_); } else { - print STDERR qq{ + $CPAN::Frontend->mywarn(qq{ Commands starting with "w" require CPAN::WAIT to be installed. Please consider installing CPAN::WAIT to use the fulltext index. For this you just need to type install CPAN::WAIT -} +}); } } else { my $ok = CPAN::Shell->try_dot_al($AUTOLOAD); if ($ok) { goto &$AUTOLOAD; - } else { - warn "not OK: $@"; +# } else { +# $CPAN::Frontend->mywarn("Could not autoload $autoload"); } - warn "CPAN::Shell doesn't know how to autoload $autoload :-( -Nothing Done. -"; - sleep 1; - CPAN::Shell->h; + $CPAN::Frontend->mywarn(qq{Unknown command '$autoload'. }. + qq{Type ? for help. +}); } } @@ -269,17 +287,11 @@ sub try_dot_al { $ok = 1; } $@ = $save; - my $lm = Carp::longmess(); +# my $lm = Carp::longmess(); # warn "ok[$ok] autoload[$autoload] longmess[$lm]"; # debug return $ok; } -# This should be left to a runtime evaluation -eval {require CPAN::WAIT;}; -unless ($@) { - unshift @ISA, "CPAN::WAIT"; -} - #### autoloader is experimental #### to try it we have to set $Try_autoload and uncomment #### the use statement and uncomment the __END__ below @@ -289,7 +301,8 @@ unless ($@) { # $Try_autoload = 1; if ($CPAN::Try_autoload) { - for my $p (qw( + my $p; + for $p (qw( CPAN::Author CPAN::Bundle CPAN::CacheMgr CPAN::Complete CPAN::Config CPAN::Debug CPAN::Distribution CPAN::FTP CPAN::FTP::netrc CPAN::Index CPAN::InfoObj CPAN::Module @@ -340,7 +353,7 @@ sub all { #-> sub CPAN::checklock ; sub checklock { my($self) = @_; - my $lockfile = CPAN->catfile($CPAN::Config->{cpan_home},".lock"); + my $lockfile = MM->catfile($CPAN::Config->{cpan_home},".lock"); if (-f $lockfile && -M _ > 0) { my $fh = FileHandle->new($lockfile); my $other = <$fh>; @@ -348,20 +361,23 @@ sub checklock { if (defined $other && $other) { chomp $other; return if $$==$other; # should never happen - print qq{There seems to be running another CPAN process }. - qq{($other). Trying to contact...\n}; + $CPAN::Frontend->mywarn( + qq{ +There seems to be running another CPAN process ($other). Contacting... +}); if (kill 0, $other) { - Carp::croak qq{Other job is running.\n}. - qq{You may want to kill it and delete the lockfile, }. - qq{maybe. On UNIX try:\n}. - qq{ kill $other\n}. - qq{ rm $lockfile\n}; + $CPAN::Frontend->mydie(qq{Other job is running. +You may want to kill it and delete the lockfile, maybe. On UNIX try: + kill $other + rm $lockfile +}); } elsif (-w $lockfile) { my($ans) = ExtUtils::MakeMaker::prompt (qq{Other job not responding. Shall I overwrite }. qq{the lockfile? (Y/N)},"y"); - print("Ok, bye\n"), exit unless $ans =~ /^y/i; + $CPAN::Frontend->myexit("Ok, bye\n") + unless $ans =~ /^y/i; } else { Carp::croak( qq{Lockfile $lockfile not writeable by you. }. @@ -379,7 +395,7 @@ sub checklock { if ($! =~ /Permission/) { my $incc = $INC{'CPAN/Config.pm'}; my $myincc = MM->catfile($ENV{HOME},'.cpan','CPAN','MyConfig.pm'); - print qq{ + $CPAN::Frontend->myprint(qq{ Your configuration suggests that CPAN.pm should use a working directory of @@ -396,17 +412,20 @@ this variable in either or $myincc -}; +}); } - Carp::croak "Could not open >$lockfile: $!"; + $CPAN::Frontend->mydie("Could not open >$lockfile: $!"); } - print $fh $$, "\n"; + $fh->print($$, "\n"); $self->{LOCK} = $lockfile; $fh->close; - $SIG{'TERM'} = sub { &cleanup; die "Got SIGTERM, leaving"; }; + $SIG{'TERM'} = sub { + &cleanup; + $CPAN::Frontend->mydie("Got SIGTERM, leaving"); + }; $SIG{'INT'} = sub { my $s = $Signal == 2 ? "a second" : "another"; - &cleanup, die "Got $s SIGINT" if $Signal; + &cleanup, $CPAN::Frontend->mydie("Got $s SIGINT") if $Signal; $Signal = 1; }; $SIG{'__DIE__'} = \&cleanup; @@ -445,43 +464,38 @@ sub has_inst { return 0; } my $file = $mod; + my $obj; $file =~ s|::|/|g; $file =~ s|/|\\|g if $^O eq 'MSWin32'; $file .= ".pm"; - if (exists $INC{$file} && $INC{$file}) { + if ($INC{$file}) { # warn "$file in %INC"; #debug return 1; - } elsif ( my($obj) = CPAN::Shell->expand('Module',$mod) ) { - if ($obj->inst_file) { - require $file; - print "CPAN: $mod successfully required\n"; - - if ($mod eq "CPAN::WAIT") { - push @CPAN::Shell::ISA, CPAN::WAIT unless $@; - } - warn $@ if $@; - return $@ ? 0 : 1; - } elsif ($mod eq "MD5"){ - print qq{ - CPAN: MD5 security checks disabled because MD5 not installed. - Please consider installing the MD5 module - -}; - sleep 2; - } } elsif (eval { require $file }) { - # we can still have luck, if the program is fed with a bogus - # database or what + # eval is good: if we haven't yet read the database it's + # perfect and if we have installed the module in the meantime, + # it tries again. The second require is only a NOOP returning + # 1 if we had success, otherwise it's retrying + $CPAN::Frontend->myprint("CPAN: $mod loaded ok\n"); + if ($mod eq "CPAN::WAIT") { + push @CPAN::Shell::ISA, CPAN::WAIT; + } return 1; } elsif ($mod eq "Net::FTP") { warn qq{ Please, install Net::FTP as soon as possible. CPAN.pm installs it for you if you just type install Bundle::libnet - Thank you. }; sleep 2; + } elsif ($mod eq "MD5"){ + $CPAN::Frontend->myprint(qq{ + CPAN: MD5 security checks disabled because MD5 not installed. + Please consider installing the MD5 module. + +}); + sleep 2; } return 0; } @@ -510,7 +524,7 @@ sub cleanup { return unless defined $META->{'LOCK'}; return unless -f $META->{'LOCK'}; unlink $META->{'LOCK'}; - print STDERR "Lockfile removed.\n"; + $CPAN::Frontend->mywarn("Lockfile removed.\n"); } package CPAN::CacheMgr; @@ -570,11 +584,11 @@ sub entries { for ($dh->read) { next if $_ eq "." || $_ eq ".."; if (-f $_) { - push @entries, $CPAN::META->catfile($dir,$_); + push @entries, MM->catfile($dir,$_); } elsif (-d _) { - push @entries, $CPAN::META->catdir($dir,$_); + push @entries, MM->catdir($dir,$_); } else { - print STDERR "Warning: weird direntry in $dir: $_\n"; + $CPAN::Frontend->mywarn("Warning: weird direntry in $dir: $_\n"); } } chdir $cwd or Carp::croak("Can't chdir to $cwd: $!"); @@ -603,8 +617,12 @@ sub disk_usage { $self->{DU} += $Du/1024/1024; if ($self->{DU} > $self->{'MAX'} ) { my($toremove) = shift @{$self->{FIFO}}; - printf "...Hold on a sec... cleaning from cache (%.1f>%.1f MB): $toremove\n", - $self->{DU}, $self->{'MAX'}; + $CPAN::Frontend->myprint(sprintf( + "...Hold on a sec... ". + "cleaning from cache ". + "(%.1f>%.1f MB): $toremove\n", + $self->{DU}, $self->{'MAX'}) + ); $self->force_clean_cache($toremove); } $self->{DU}; @@ -658,23 +676,17 @@ sub debug { ($caller) = caller(0); $caller =~ s/.*:://; $arg = "" unless defined $arg; - my $rest = join ":", map { defined $_ ? $_ : "UNDEF" } @rest; -# print "caller[$caller]\n"; -# print "func[$func]\n"; -# print "line[$line]\n"; -# print "rest[@rest]\n"; -# print "CPAN::DEBUG{caller}[$CPAN::DEBUG{$caller}]\n"; -# print "CPAN::DEBUG[$CPAN::DEBUG]\n"; + my $rest = join "|", map { defined $_ ? $_ : "UNDEF" } @rest; if ($CPAN::DEBUG{$caller} & $CPAN::DEBUG){ if ($arg and ref $arg) { eval { require Data::Dumper }; if ($@) { - print $arg->as_string; + $CPAN::Frontend->myprint($arg->as_string); } else { - print Data::Dumper::Dumper($arg); + $CPAN::Frontend->myprint(Data::Dumper::Dumper($arg)); } } else { - print "Debug($caller:$func,$line,[$rest]): $arg\n" + $CPAN::Frontend->myprint("Debug($caller:$func,$line,[$rest]): $arg\n"); } } } @@ -709,17 +721,18 @@ sub edit { } elsif (@args) { $CPAN::Config->{$o} = [@args]; } else { - print( - " $o ", - ExtUtils::MakeMaker::neatvalue($CPAN::Config->{$o}), - "\n" + $CPAN::Frontend->myprint( + join "", + " $o ", + ExtUtils::MakeMaker::neatvalue($CPAN::Config->{$o}), + "\n" ); } } else { $CPAN::Config->{$o} = $args[0] if defined $args[0]; - print " $o "; - print defined $CPAN::Config->{$o} ? - $CPAN::Config->{$o} : "UNDEFINED"; + $CPAN::Frontend->myprint(" $o " . + (defined $CPAN::Config->{$o} ? + $CPAN::Config->{$o} : "UNDEFINED")); } } } @@ -755,7 +768,7 @@ EOF $msg ||= "\n"; my($fh) = FileHandle->new; open $fh, ">$configpm" or warn "Couldn't open >$configpm: $!"; - print $fh qq[$msg\$CPAN::Config = \{\n]; + $fh->print(qq[$msg\$CPAN::Config = \{\n]); foreach (sort keys %$CPAN::Config) { $fh->print( " '$_' => ", @@ -764,13 +777,13 @@ EOF ); } - print $fh "};\n1;\n__END__\n"; + $fh->print("};\n1;\n__END__\n"); close $fh; #$mode = 0444 | ( $mode & 0111 ? 0111 : 0 ); #chmod $mode, $configpm; ###why was that so? $self->defaults; - print "commit: wrote $configpm\n"; + $CPAN::Frontend->myprint("commit: wrote $configpm\n"); 1; } @@ -798,10 +811,13 @@ sub init { sub load { my($self) = shift; my(@miss); - eval {require CPAN::Config;}; # We eval, because of some MakeMaker problems - unshift @INC, $CPAN::META->catdir($ENV{HOME},".cpan") unless $dot_cpan++; - eval {require CPAN::MyConfig;}; # where you can override system wide settings + eval {require CPAN::Config;}; # We eval because of some + # MakeMaker problems + unshift @INC, MM->catdir($ENV{HOME},".cpan") unless $dot_cpan++; + eval {require CPAN::MyConfig;}; # where you can override + # system wide settings return unless @miss = $self->not_loaded; + # XXX better check for arrayrefs too require CPAN::FirstTime; my($configpm,$fh,$redo,$theycalled); $redo ||= ""; @@ -856,14 +872,14 @@ sub load { } } local($") = ", "; - print qq{ + $CPAN::Frontend->myprint(qq{ We have to reconfigure CPAN.pm due to following uninitialized parameters: @miss -} if $redo && ! $theycalled; - print qq{ +}) if $redo && ! $theycalled; + $CPAN::Frontend->myprint(qq{ $configpm initialized. -}; +}); sleep 2; CPAN::FirstTime::init($configpm); } @@ -890,7 +906,7 @@ sub unload { *h = \&help; #-> sub CPAN::Config::help ; sub help { - print <myprint(qq{ Known options: defaults reload default config values from disk commit commit session changes to disk @@ -906,7 +922,7 @@ You may edit key values in the follow fashion: o conf urllist unshift ftp://ftp.foo.bar/ -EOF +}); undef; #don't reprint CPAN::Config } @@ -914,6 +930,17 @@ EOF sub cpl { my($word,$line,$pos) = @_; $word ||= ""; + CPAN->debug("word[$word] line[$line] pos[$pos]") if $CPAN::DEBUG; + my(@words) = split " ", substr($line,0,$pos+1); + if ( + $words[2] =~ /list$/ && @words == 3 + || + $words[2] =~ /list$/ && @words == 4 && length($word) + ) { + return grep /^\Q$word\E/, qw(splice shift unshift pop push); + } elsif (@words >= 4) { + return (); + } my(@o_conf) = (keys %CPAN::Config::can, keys %$CPAN::Config); return grep /^\Q$word\E/, @o_conf; } @@ -924,9 +951,9 @@ package CPAN::Shell; sub h { my($class,$about) = @_; if (defined $about) { - print "Detailed help not yet implemented\n"; + $CPAN::Frontend->myprint("Detailed help not yet implemented\n"); } else { - print q{ + $CPAN::Frontend->myprint(q{ command arguments description a string authors b or display bundles @@ -949,34 +976,34 @@ h or ? display this menu o various set and query options ! perl-code eval a perl command q quit the shell subroutine -}; +}); } } #-> sub CPAN::Shell::a ; -sub a { print shift->format_result('Author',@_);} +sub a { $CPAN::Frontend->myprint(shift->format_result('Author',@_));} #-> sub CPAN::Shell::b ; sub b { my($self,@which) = @_; CPAN->debug("which[@which]") if $CPAN::DEBUG; my($incdir,$bdir,$dh); foreach $incdir ($CPAN::Config->{'cpan_home'},@INC) { - $bdir = $CPAN::META->catdir($incdir,"Bundle"); + $bdir = MM->catdir($incdir,"Bundle"); if ($dh = DirHandle->new($bdir)) { # may fail my($entry); for $entry ($dh->read) { - next if -d $CPAN::META->catdir($bdir,$entry); + next if -d MM->catdir($bdir,$entry); next unless $entry =~ s/\.pm$//; $CPAN::META->instance('CPAN::Bundle',"Bundle::$entry"); } } } - print $self->format_result('Bundle',@which); + $CPAN::Frontend->myprint($self->format_result('Bundle',@which)); } #-> sub CPAN::Shell::d ; -sub d { print shift->format_result('Distribution',@_);} +sub d { $CPAN::Frontend->myprint(shift->format_result('Distribution',@_));} #-> sub CPAN::Shell::m ; -sub m { print shift->format_result('Module',@_);} +sub m { $CPAN::Frontend->myprint(shift->format_result('Module',@_));} #-> sub CPAN::Shell::i ; sub i { @@ -993,7 +1020,7 @@ sub i { $result[0]->as_string : join "", map {$_->as_glimpse} @result; $result ||= "No objects found of any type for argument @args\n"; - print $result; + $CPAN::Frontend->myprint($result); } #-> sub CPAN::Shell::o ; @@ -1005,24 +1032,32 @@ sub o { shift @o_what if @o_what && $o_what[0] eq 'help'; if (!@o_what) { my($k,$v); - print "CPAN::Config options:\n"; + $CPAN::Frontend->myprint("CPAN::Config options:\n"); for $k (sort keys %CPAN::Config::can) { $v = $CPAN::Config::can{$k}; - printf " %-18s %s\n", $k, $v; + $CPAN::Frontend->myprint(sprintf " %-18s %s\n", $k, $v); } - print "\n"; + $CPAN::Frontend->myprint("\n"); for $k (sort keys %$CPAN::Config) { $v = $CPAN::Config->{$k}; if (ref $v) { - printf " %-18s\n", $k; - print map {"\t$_\n"} @{$v}; + $CPAN::Frontend->myprint( + join( + "", + sprintf( + " %-18s\n", + $k + ), + map {"\t$_\n"} @{$v} + ) + ); } else { - printf " %-18s %s\n", $k, $v; + $CPAN::Frontend->myprint(sprintf " %-18s %s\n", $k, $v); } } - print "\n"; + $CPAN::Frontend->myprint("\n"); } elsif (!CPAN::Config->edit(@o_what)) { - print qq[Type 'o conf' to view configuration edit options\n\n]; + $CPAN::Frontend->myprint(qq[Type 'o conf' to view configuration edit options\n\n]); } } elsif ($o_type eq 'debug') { my(%valid); @@ -1047,31 +1082,32 @@ sub o { $CPAN::DEBUG |= $CPAN::DEBUG{$_}; $known = 1; } - print "unknown argument [$what]\n" unless $known; + $CPAN::Frontend->myprint("unknown argument [$what]\n") + unless $known; } } } else { - print "Valid options for debug are ". - join(", ",sort(keys %CPAN::DEBUG), 'all'). + $CPAN::Frontend->myprint("Valid options for debug are ". + join(", ",sort(keys %CPAN::DEBUG), 'all'). qq{ or a number. Completion works on the options. }. - qq{Case is ignored.\n\n}; + qq{Case is ignored.\n\n}); } if ($CPAN::DEBUG) { - print "Options set for debugging:\n"; + $CPAN::Frontend->myprint("Options set for debugging:\n"); my($k,$v); for $k (sort {$CPAN::DEBUG{$a} <=> $CPAN::DEBUG{$b}} keys %CPAN::DEBUG) { $v = $CPAN::DEBUG{$k}; - printf " %-14s(%s)\n", $k, $v if $v & $CPAN::DEBUG; + $CPAN::Frontend->myprint(sprintf " %-14s(%s)\n", $k, $v) if $v & $CPAN::DEBUG; } } else { - print "Debugging turned off completely.\n"; + $CPAN::Frontend->myprint("Debugging turned off completely.\n"); } } else { - print qq{ + $CPAN::Frontend->myprint(qq{ Known options: conf set or get configuration variables debug set or get debugging options -}; +}); } } @@ -1091,19 +1127,20 @@ sub reload { if ( $_[0] =~ /Subroutine \w+ redefined/ ) { ++$redef; local($|) = 1; - print "."; + $CPAN::Frontend->myprint("."); return; } warn @_; }; eval <$fh>; warn $@ if $@; - print "\n$redef subroutines redefined\n"; + $CPAN::Frontend->myprint("\n$redef subroutines redefined\n"); } elsif ($command =~ /index/) { CPAN::Index->force_reload; } else { - print qq{cpan re-evals the CPAN.pm file\n}; - print qq{index re-reads the index files\n}; + $CPAN::Frontend->myprint(qq{cpan re-evals the CPAN.pm file +index re-reads the index files +}); } } @@ -1111,18 +1148,19 @@ sub reload { sub _binary_extensions { my($self) = shift @_; my(@result,$module,%seen,%need,$headerdone); + my $isaperl = q{perl5[._-]\\d{3}(_[0-4][0-9])?\\.tar[._-]gz$}; for $module ($self->expand('Module','/./')) { my $file = $module->cpan_file; next if $file eq "N/A"; next if $file =~ /^Contact Author/; - next if $file =~ /perl5[._-]\d{3}(?:[\d_]+)?\.tar[._-]gz$/; + next if $file =~ / $isaperl /xo; next unless $module->xs_file; local($|) = 1; - print "."; + $CPAN::Frontend->myprint("."); push @result, $module; } # print join " | ", @result; - print "\n"; + $CPAN::Frontend->myprint("\n"); return @result; } @@ -1131,14 +1169,15 @@ sub recompile { my($self) = shift @_; my($module,@module,$cpan_file,%dist); @module = $self->_binary_extensions(); - for $module (@module){ # we force now and compile later, so we don't do it twice + for $module (@module){ # we force now and compile later, so we + # don't do it twice $cpan_file = $module->cpan_file; my $pack = $CPAN::META->instance('CPAN::Distribution',$cpan_file); $pack->force; $dist{$cpan_file}++; } for $cpan_file (sort keys %dist) { - print " CPAN: Recompiling $cpan_file\n\n"; + $CPAN::Frontend->myprint(" CPAN: Recompiling $cpan_file\n\n"); my $pack = $CPAN::META->instance('CPAN::Distribution',$cpan_file); $pack->install; $CPAN::Signal = 0; # it's tempting to reset Signal, so we can @@ -1156,13 +1195,14 @@ sub _u_r_common { Carp::croak "Usage: \$obj->_u_r_common(a|r|u)" unless $what =~ /^[aru]$/; my(@args) = @_; @args = '/./' unless @args; - my(@result,$module,%seen,%need,$headerdone,$version_zeroes); - $version_zeroes = 0; + my(@result,$module,%seen,%need,$headerdone, + $version_undefs,$version_zeroes); + $version_undefs = $version_zeroes = 0; my $sprintf = "%-25s %9s %9s %s\n"; for $module ($self->expand('Module',@args)) { my $file = $module->cpan_file; next unless defined $file; # ?? - my($latest) = $module->cpan_version || 0; + my($latest) = $module->cpan_version; my($inst_file) = $module->inst_file; my($have); if ($inst_file){ @@ -1171,8 +1211,15 @@ sub _u_r_common { } elsif ($what eq "r") { $have = $module->inst_version; local($^W) = 0; - $version_zeroes++ unless $have; + if ($have eq "undef"){ + $version_undefs++; + } elsif ($have == 0){ + $version_zeroes++; + } next if $have >= $latest; +# to be pedantic we should probably say: +# && !($have eq "undef" && $latest ne "undef" && $latest gt ""); +# to catch the case where CPAN has a version 0 and we have a version undef } elsif ($what eq "u") { next; } @@ -1198,30 +1245,38 @@ sub _u_r_common { next if $file =~ /^Contact/; } unless ($headerdone++){ - print "\n"; - printf( + $CPAN::Frontend->myprint("\n"); + $CPAN::Frontend->myprint(sprintf( $sprintf, "Package namespace", "installed", "latest", "in CPAN file" - ); + )); } $latest = substr($latest,0,8) if length($latest) > 8; $have = substr($have,0,8) if length($have) > 8; - printf $sprintf, $module->id, $have, $latest, $file; + $CPAN::Frontend->myprint(sprintf $sprintf, $module->id, $have, $latest, $file); $need{$module->id}++; } unless (%need) { if ($what eq "u") { - print "No modules found for @args\n"; + $CPAN::Frontend->myprint("No modules found for @args\n"); } elsif ($what eq "r") { - print "All modules are up to date for @args\n"; + $CPAN::Frontend->myprint("All modules are up to date for @args\n"); } } - if ($what eq "r" && $version_zeroes) { - my $s = $version_zeroes > 1 ? "s have" : " has"; - print qq{$version_zeroes installed module$s no version number to compare\n}; + if ($what eq "r") { + if ($version_zeroes) { + my $s_has = $version_zeroes > 1 ? "s have" : " has"; + $CPAN::Frontend->myprint(qq{$version_zeroes installed module$s_has }. + qq{a version number of 0\n}); + } + if ($version_undefs) { + my $s_has = $version_undefs > 1 ? "s have" : " has"; + $CPAN::Frontend->myprint(qq{$version_undefs installed module$s_has no }. + qq{parseable version number\n}); + } } @result; } @@ -1240,10 +1295,10 @@ sub u { sub autobundle { my($self) = shift; my(@bundle) = $self->_u_r_common("a",@_); - my($todir) = $CPAN::META->catdir($CPAN::Config->{'cpan_home'},"Bundle"); + my($todir) = MM->catdir($CPAN::Config->{'cpan_home'},"Bundle"); File::Path::mkpath($todir); unless (-d $todir) { - print "Couldn't mkdir $todir for some reason\n"; + $CPAN::Frontend->myprint("Couldn't mkdir $todir for some reason\n"); return; } my($y,$m,$d) = (localtime)[5,4,3]; @@ -1251,10 +1306,10 @@ sub autobundle { $m++; my($c) = 0; my($me) = sprintf "Snapshot_%04d_%02d_%02d_%02d", $y, $m, $d, $c; - my($to) = $CPAN::META->catfile($todir,"$me.pm"); + my($to) = MM->catfile($todir,"$me.pm"); while (-f $to) { $me = sprintf "Snapshot_%04d_%02d_%02d_%02d", $y, $m, $d, ++$c; - $to = $CPAN::META->catfile($todir,"$me.pm"); + $to = MM->catfile($todir,"$me.pm"); } my($fh) = FileHandle->new(">$to") or Carp::croak "Can't open >$to: $!"; $fh->print( @@ -1278,8 +1333,8 @@ sub autobundle { "by the autobundle routine in CPAN.pm.\n", ); $fh->close; - print "\nWrote bundle file - $to\n\n"; + $CPAN::Frontend->myprint("\nWrote bundle file + $to\n\n"); } #-> sub CPAN::Shell::expand ; @@ -1341,6 +1396,67 @@ sub format_result { $result; } +# The only reason for this method is currently to have a reliable +# debugging utility that reveals which output is going through which +# channel. No, I don't like the colors ;-) +sub print_ornamented { + my($self,$what,$ornament) = @_; + my $longest = 0; + my $ornamenting = 0; # turn the colors on + + if ($ornamenting) { + unless (defined &color) { + if ($CPAN::META->has_inst("Term::ANSIColor")) { + import Term::ANSIColor "color"; + } else { + *color = sub { return "" }; + } + } + for my $line (split /\n/, $what) { + $longest = length($line) if length($line) > $longest; + } + my $sprintf = "%-" . $longest . "s"; + while ($what){ + $what =~ s/(.*\n?)//m; + my $line = $1; + last unless $line; + my($nl) = chomp $line ? "\n" : ""; + # print "line[$line]ornament[$ornament]sprintf[$sprintf]\n"; + print color($ornament), sprintf($sprintf,$line), color("reset"), $nl; + } + } else { + print $what; + } +} + +sub myprint { + my($self,$what) = @_; + $self->print_ornamented($what, 'bold blue on_yellow'); +} + +sub myexit { + my($self,$what) = @_; + $self->myprint($what); + exit; +} + +sub mywarn { + my($self,$what) = @_; + $self->print_ornamented($what, 'bold red on_yellow'); +} + +sub myconfess { + my($self,$what) = @_; + $self->print_ornamented($what, 'bold red on_white'); + Carp::confess "died"; +} + +sub mydie { + my($self,$what) = @_; + $self->print_ornamented($what, 'bold red on_white'); + die "\n"; +} + #-> sub CPAN::Shell::rematein ; sub rematein { shift; @@ -1378,15 +1494,20 @@ sub rematein { $obj->$meth(); } elsif ($CPAN::META->exists('CPAN::Author',$s)) { $obj = $CPAN::META->instance('CPAN::Author',$s); - print "Don't be silly, you can't $meth ", $obj->fullname, " ;-)\n"; + $CPAN::Frontend->myprint( + join "", + "Don't be silly, you can't $meth ", + $obj->fullname, + " ;-)\n" + ); } else { - print qq{Warning: Cannot $meth $s, don\'t know what it is. + $CPAN::Frontend->myprint(qq{Warning: Cannot $meth $s, don\'t know what it is. Try the command i /$s/ to find objects with similar identifiers. -}; +}); } } } @@ -1425,7 +1546,6 @@ sub ftp_get { warn "Couldn't login on $host"; return; } - # print qq[Going to ->cwd("$dir")\n]; unless ( $ftp->cwd($dir) ){ warn "Couldn't cwd $dir"; return; @@ -1440,6 +1560,22 @@ sub ftp_get { return 1; } +sub is_reachable { + my($self,$url) = @_; + return 1; # we can't simply roll our own, firewalls may break ping + return 0 unless $url; + return 1 if substr($url,0,4) eq "file"; + return 1 unless $url =~ m|://([^/]+)|; + my $host = $1; + require Net::Ping; + return 1 unless $Net::Ping::VERSION >= 2; + my $p; + eval {$p = Net::Ping->new("icmp");}; + eval {$p = Net::Ping->new("tcp");} if $@; + $CPAN::Frontend->mydie($@) if $@; + return $p->ping($host, 3); +} + #-> sub CPAN::FTP::localize ; # sorry for the ugly code here, I'll clean it up as soon as Net::FTP # is in the core @@ -1451,7 +1587,7 @@ sub localize { $self->debug("file[$file] aslocal[$aslocal] force[$force]") if $CPAN::DEBUG; - return $aslocal if -f $aslocal && -r _ && ! $force; + return $aslocal if -f $aslocal && -r _ && !($force & 1); my($restore) = 0; if (-f $aslocal){ rename $aslocal, "$aslocal.bak"; @@ -1460,10 +1596,10 @@ sub localize { my($aslocal_dir) = File::Basename::dirname($aslocal); File::Path::mkpath($aslocal_dir); - print STDERR qq{Warning: You are not allowed to write into }. + $CPAN::Frontend->mywarn(qq{Warning: You are not allowed to write into }. qq{directory "$aslocal_dir". - I\'ll continue, but if you face any problems, they may be due - to insufficient permissions.\n} unless -w $aslocal_dir; + I\'ll continue, but if you encounter problems, they may be due + to insufficient permissions.\n}) unless -w $aslocal_dir; # Inheritance is not easier to manage than a few if/else branches if ($CPAN::META->has_inst('LWP')) { @@ -1482,12 +1618,78 @@ sub localize { # Try the list of urls for each single object. We keep a record # where we did get a file from + my(@reordered,$last); +#line 1621 + $last = $#{$CPAN::Config->{urllist}}; + if ($force & 2) { # local cpans probably out of date, don't reorder + @reordered = (0..$last); + } else { + @reordered = + sort { + (substr($CPAN::Config->{urllist}[$b],0,4) eq "file") + <=> + (substr($CPAN::Config->{urllist}[$a],0,4) eq "file") + or + defined($Thesite) + and + ($b == $Thesite) + <=> + ($a == $Thesite) + } 0..$last; + +# ((grep { substr($CPAN::Config->{urllist}[$_],0,4) +# eq "file" } 0..$last), +# (grep { substr($CPAN::Config->{urllist}[$_],0,4) +# ne "file" } 0..$last)); + } + my($level,@levels); + if ($Themethod) { + @levels = ($Themethod, grep {$_ ne $Themethod} qw/easy hard hardest/); + } else { + @levels = qw/easy hard hardest/; + } + for $level (@levels) { + my $method = "host$level"; + my @host_seq = $level eq "easy" ? + @reordered : 0..$last; # reordered has CDROM up front + my $ret = $self->$method(\@host_seq,$file,$aslocal); + if ($ret) { + $Themethod = $level; + $self->debug("level[$level]") if $CPAN::DEBUG; + return $ret; + } + } + my(@mess); + push @mess, + qq{Please check, if the URLs I found in your configuration file \(}. + join(", ", @{$CPAN::Config->{urllist}}). + qq{\) are valid. The urllist can be edited.}, + qq{E.g. with ``o conf urllist push ftp://myurl/''}; + $CPAN::Frontend->myprint(Text::Wrap::wrap("","",@mess). "\n\n"); + sleep 2; + $CPAN::Frontend->myprint("Cannot fetch $file\n\n"); + if ($restore) { + rename "$aslocal.bak", $aslocal; + $CPAN::Frontend->myprint("Trying to get away with old file:\n" . + $self->ls($aslocal)); + return $aslocal; + } + return; +} + +sub hosteasy { + my($self,$host_seq,$file,$aslocal) = @_; my($i); - for $i (0..$#{$CPAN::Config->{urllist}}) { + HOSTEASY: for $i (@$host_seq) { my $url = $CPAN::Config->{urllist}[$i]; + unless ($self->is_reachable($url)) { + $CPAN::Frontend->myprint("Skipping $url (seems to be not reachable)\n"); + sleep 2; + next; + } $url .= "/" unless substr($url,-1) eq "/"; $url .= $file; - $self->debug("localizing[$url]") if $CPAN::DEBUG; + $self->debug("localizing perlish[$url]") if $CPAN::DEBUG; if ($url =~ /^file:/) { my $l; if ($CPAN::META->has_inst('LWP')) { @@ -1495,27 +1697,51 @@ sub localize { my $u = URI::URL->new($url); $l = $u->path; } else { # works only on Unix, is poorly constructed, but - # hopefully better than nothing. - # RFC 1738 says fileurl BNF is - # fileurl = "file://" [ host | "localhost" ] "/" fpath - # Thanks to "Mark D. Baushke" for the code + # hopefully better than nothing. + # RFC 1738 says fileurl BNF is + # fileurl = "file://" [ host | "localhost" ] "/" fpath + # Thanks to "Mark D. Baushke" for + # the code ($l = $url) =~ s,^file://[^/]+,,; # discard the host part $l =~ s/^file://; # assume they meant file://localhost } - return $l if -f $l && -r _; + if ( -f $l && -r _) { + $Thesite = $i; + return $l; + } # Maybe mirror has compressed it? if (-f "$l.gz") { $self->debug("found compressed $l.gz") if $CPAN::DEBUG; system("$CPAN::Config->{gzip} -dc $l.gz > $aslocal"); - return $aslocal if -f $aslocal; + if ( -f $aslocal) { + $Thesite = $i; + return $aslocal; + } } } - if ($CPAN::META->has_inst('LWP')) { - print "Fetching $url with LWP\n"; + $CPAN::Frontend->myprint("Fetching with LWP: + $url +"); my $res = $Ua->mirror($url, $aslocal); if ($res->is_success) { + $Thesite = $i; return $aslocal; + } elsif ($url !~ /\.gz$/) { + my $gzurl = "$url.gz"; + $CPAN::Frontend->myprint("Fetching with LWP: + $gzurl +"); + $res = $Ua->mirror($gzurl, "$aslocal.gz"); + if ($res->is_success && + system("$CPAN::Config->{gzip} -d $aslocal.gz")==0) { + $Thesite = $i; + return $aslocal; + } else { + next HOSTEASY ; + } + } else { + next HOSTEASY ; } } if ($url =~ m|^ftp://(.*?)/(.*)/(.*)|) { @@ -1523,202 +1749,259 @@ sub localize { my($host,$dir,$getfile) = ($1,$2,$3); if ($CPAN::META->has_inst('Net::FTP')) { $dir =~ s|/+|/|g; - $self->debug("Going to fetch file [$getfile] - from dir [$dir] - on host [$host] - as local [$aslocal]") if $CPAN::DEBUG; - CPAN::FTP->ftp_get($host,$dir,$getfile,$aslocal) && return $aslocal; - warn "Net::FTP failed for some reason\n"; + $CPAN::Frontend->myprint("Fetching with Net::FTP: + $aslocal +"); + $self->debug("getfile[$getfile]dir[$dir]host[$host]" . + "aslocal[$aslocal]") if $CPAN::DEBUG; + if (CPAN::FTP->ftp_get($host,$dir,$getfile,$aslocal)) { + $Thesite = $i; + return $aslocal; + } + if ($aslocal !~ /\.gz$/) { + my $gz = "$aslocal.gz"; + $CPAN::Frontend->myprint("Fetching with Net::FTP + $gz +"); + if (CPAN::FTP->ftp_get($host, + $dir, + "$getfile.gz", + $gz) && + system("$CPAN::Config->{gzip} -d $gz")==0 ){ + $Thesite = $i; + return $aslocal; + } + } + next HOSTEASY; } } + } +} - # Came back if Net::FTP couldn't establish connection (or failed otherwise) - # Maybe they are behind a firewall, but they gave us - # a socksified (or other) ftp program... +sub hosthard { + my($self,$host_seq,$file,$aslocal) = @_; - my($funkyftp); - # does ncftp handle http? - for $funkyftp ($CPAN::Config->{'lynx'},$CPAN::Config->{'ncftp'}) { + # Came back if Net::FTP couldn't establish connection (or + # failed otherwise) Maybe they are behind a firewall, but they + # gave us a socksified (or other) ftp program... + + my($i); + my($aslocal_dir) = File::Basename::dirname($aslocal); + File::Path::mkpath($aslocal_dir); + HOSTHARD: for $i (@$host_seq) { + my $url = $CPAN::Config->{urllist}[$i]; + unless ($self->is_reachable($url)) { + $CPAN::Frontend->myprint("Skipping $url (not reachable)\n"); + next; + } + $url .= "/" unless substr($url,-1) eq "/"; + $url .= $file; + my($host,$dir,$getfile); + if ($url =~ m|^ftp://(.*?)/(.*)/(.*)|) { + ($host,$dir,$getfile) = ($1,$2,$3); + } else { + next HOSTHARD; # who said, we could ftp anything except ftp? + } + $self->debug("localizing funkyftpwise[$url]") if $CPAN::DEBUG; + my($f,$funkyftp); + for $f ('lynx','ncftp') { + next unless exists $CPAN::Config->{$f}; + $funkyftp = $CPAN::Config->{$f}; next unless defined $funkyftp; next if $funkyftp =~ /^\s*$/; my($want_compressed); - print( - qq{ -Trying with $funkyftp to get - $url -}); - $want_compressed = $aslocal =~ s/\.gz//; + my $aslocal_uncompressed; + ($aslocal_uncompressed = $aslocal) =~ s/\.gz//; my($source_switch) = ""; $source_switch = "-source" if $funkyftp =~ /\blynx$/; $source_switch = "-c" if $funkyftp =~ /\bncftp$/; - my($system) = "$funkyftp $source_switch '$url' > $aslocal"; + $CPAN::Frontend->myprint( + qq{ +Trying with "$funkyftp $source_switch" to get + $url +}); + my($system) = "$funkyftp $source_switch '$url' > ". + "$aslocal_uncompressed"; $self->debug("system[$system]") if $CPAN::DEBUG; my($wstatus); if (($wstatus = system($system)) == 0 && - -s $aslocal # lynx returns 0 on my system even if it fails + -s $aslocal_uncompressed # lynx returns 0 on my + # system even if it fails ) { - if ($want_compressed) { - $system = "$CPAN::Config->{'gzip'} -dt $aslocal"; + if ($aslocal_uncompressed ne $aslocal) { + # test gzip integrity + $system = + "$CPAN::Config->{'gzip'} -dt $aslocal_uncompressed"; if (system($system) == 0) { - rename $aslocal, "$aslocal.gz"; + rename $aslocal_uncompressed, $aslocal; } else { - $system = "$CPAN::Config->{'gzip'} $aslocal"; + $system = + "$CPAN::Config->{'gzip'} $aslocal_uncompressed"; system($system); } - return "$aslocal.gz"; - } else { - $system = "$CPAN::Config->{'gzip'} -dt $aslocal"; + $Thesite = $i; + return $aslocal; + } + } elsif ($url !~ /\.gz$/) { + my $gz = "$aslocal.gz"; + my $gzurl = "$url.gz"; + $CPAN::Frontend->myprint( + qq{ +Trying with "$funkyftp $source_switch" to get + $url.gz +}); + my($system) = "$funkyftp $source_switch '$url.gz' > ". + "$aslocal_uncompressed.gz"; + $self->debug("system[$system]") if $CPAN::DEBUG; + my($wstatus); + if (($wstatus = system($system)) == 0 + && + -s "$aslocal_uncompressed.gz" + ) { + # test gzip integrity + $system = + "$CPAN::Config->{'gzip'} -dt $aslocal_uncompressed.gz"; + $CPAN::Frontend->mywarn("system[$system]"); if (system($system) == 0) { - $system = "$CPAN::Config->{'gzip'} -d $aslocal"; + $system = "$CPAN::Config->{'gzip'} -dc ". + "$aslocal_uncompressed.gz > $aslocal"; + $CPAN::Frontend->mywarn("system[$system]"); system($system); } else { - # should be fine, eh? + rename $aslocal_uncompressed, $aslocal; } +#line 1739 + $Thesite = $i; return $aslocal; } } else { my $estatus = $wstatus >> 8; - my $size = -s $aslocal; - print qq{ + my $size = -f $aslocal ? ", left\n$aslocal with size ".-s _ : ""; + $CPAN::Frontend->myprint(qq{ System call "$system" -returned status $estatus (wstat $wstatus), left -$aslocal with size $size -}; +returned status $estatus (wstat $wstatus)$size +}); } } + } +} - if ($url =~ m|^ftp://(.*?)/(.*)/(.*)|) { - my($host,$dir,$getfile) = ($1,$2,$3); - my($netrcfile,$fh); - if (-x $CPAN::Config->{'ftp'}) { - my $timestamp = 0; - my($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime, - $ctime,$blksize,$blocks) = stat($aslocal); - $timestamp = $mtime ||= 0; - - my($netrc) = CPAN::FTP::netrc->new; - my($verbose) = $CPAN::DEBUG{'FTP'} & $CPAN::DEBUG ? " -v" : ""; - - my $targetfile = File::Basename::basename($aslocal); - my(@dialog); - push( - @dialog, - "lcd $aslocal_dir", - "cd /", - map("cd $_", split "/", $dir), # RFC 1738 - "bin", - "get $getfile $targetfile", - "quit" - ); - if (! $netrc->netrc) { - CPAN->debug("No ~/.netrc file found") if $CPAN::DEBUG; - } elsif ($netrc->hasdefault || $netrc->contains($host)) { - CPAN->debug( - sprint( - "hasdef[%d]cont($host)[%d]", - $netrc->hasdefault, - $netrc->contains($host) - ) - ) if $CPAN::DEBUG; - if ($netrc->protected) { - print( - qq{ +sub hosthardest { + my($self,$host_seq,$file,$aslocal) = @_; + + my($i); + my($aslocal_dir) = File::Basename::dirname($aslocal); + File::Path::mkpath($aslocal_dir); + HOSTHARDEST: for $i (@$host_seq) { + unless (length $CPAN::Config->{'ftp'}) { + $CPAN::Frontend->myprint("No external ftp command available\n\n"); + last HOSTHARDEST; + } + my $url = $CPAN::Config->{urllist}[$i]; + unless ($self->is_reachable($url)) { + $CPAN::Frontend->myprint("Skipping $url (not reachable)\n"); + next; + } + $url .= "/" unless substr($url,-1) eq "/"; + $url .= $file; + $self->debug("localizing ftpwise[$url]") if $CPAN::DEBUG; + unless ($url =~ m|^ftp://(.*?)/(.*)/(.*)|) { + next; + } + my($host,$dir,$getfile) = ($1,$2,$3); + my($netrcfile,$fh); + my $timestamp = 0; + my($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime, + $ctime,$blksize,$blocks) = stat($aslocal); + $timestamp = $mtime ||= 0; + my($netrc) = CPAN::FTP::netrc->new; + my($verbose) = $CPAN::DEBUG{'FTP'} & $CPAN::DEBUG ? " -v" : ""; + my $targetfile = File::Basename::basename($aslocal); + my(@dialog); + push( + @dialog, + "lcd $aslocal_dir", + "cd /", + map("cd $_", split "/", $dir), # RFC 1738 + "bin", + "get $getfile $targetfile", + "quit" + ); + if (! $netrc->netrc) { + CPAN->debug("No ~/.netrc file found") if $CPAN::DEBUG; + } elsif ($netrc->hasdefault || $netrc->contains($host)) { + CPAN->debug(sprintf("hasdef[%d]cont($host)[%d]", + $netrc->hasdefault, + $netrc->contains($host))) if $CPAN::DEBUG; + if ($netrc->protected) { + $CPAN::Frontend->myprint(qq{ Trying with external ftp to get $url As this requires some features that are not thoroughly tested, we\'re not sure, that we get it right.... } - ); - my $fh = FileHandle->new; - $fh->open("|$CPAN::Config->{'ftp'}$verbose $host") - or die "Couldn't open ftp: $!"; - # pilot is blind now - CPAN->debug("dialog [".(join "|",@dialog)."]") - if $CPAN::DEBUG; - foreach (@dialog) { $fh->print("$_\n") } - $fh->close; # Wait for process to complete - my $wstatus = $?; - my $estatus = $wstatus >> 8; - print qq{ -Subprocess "|$CPAN::Config->{'ftp'}$verbose $host" - returned status $estatus (wstat $wstatus) -} if $wstatus; - ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, - $atime,$mtime,$ctime,$blksize,$blocks) = stat($aslocal); - $mtime ||= 0; - if ($mtime > $timestamp) { - print "GOT $aslocal\n"; - return $aslocal; - } else { - print "Hmm... Still failed!\n"; - } - } else { - warn "Your $netrcfile is not correctly protected.\n"; - } - } else { - warn "Your ~/.netrc neither contains $host - nor does it have a default entry\n"; - } - - # OK, they don't have a valid ~/.netrc. Use 'ftp -n' then and - # login manually to host, using e-mail as password. - print qq{Issuing "$CPAN::Config->{'ftp'}$verbose -n"\n}; - unshift( - @dialog, - "open $host", - "user anonymous $Config::Config{'cf_email'}" - ); - CPAN->debug("dialog [".(join "|",@dialog)."]") if $CPAN::DEBUG; - $fh = FileHandle->new; - $fh->open("|$CPAN::Config->{'ftp'}$verbose -n") or - die "Cannot fork: $!\n"; - foreach (@dialog) { $fh->print("$_\n") } - $fh->close; - my $wstatus = $?; - my $estatus = $wstatus >> 8; - print qq{ -Subprocess "|$CPAN::Config->{'ftp'}$verbose -n" - returned status $estatus (wstat $wstatus) -} if $wstatus; + ); + $self->talk_ftp("$CPAN::Config->{'ftp'}$verbose $host", + @dialog); ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, - $atime,$mtime,$ctime,$blksize,$blocks) = stat($aslocal); + $atime,$mtime,$ctime,$blksize,$blocks) = stat($aslocal); $mtime ||= 0; if ($mtime > $timestamp) { - print "GOT $aslocal\n"; + $CPAN::Frontend->myprint("GOT $aslocal\n"); + $Thesite = $i; return $aslocal; } else { - print "Bad luck... Still failed!\n"; + $CPAN::Frontend->myprint("Hmm... Still failed!\n"); } + } else { + $CPAN::Frontend->mywarn(qq{Your $netrcfile is not }. + qq{correctly protected.\n}); } - sleep 2; + } else { + $CPAN::Frontend->mywarn("Your ~/.netrc neither contains $host + nor does it have a default entry\n"); } - - print "Can't access URL $url.\n\n"; - my(@mess,$mess); - push @mess, "LWP" unless CPAN->has_inst('LWP'); - push @mess, "Net::FTP" unless CPAN->has_inst('Net::FTP'); - my($ext); - for $ext (qw/lynx ncftp ftp/) { - $CPAN::Config->{$ext} ||= ""; - push @mess, "an external $ext" unless -x $CPAN::Config->{$ext}; + + # OK, they don't have a valid ~/.netrc. Use 'ftp -n' + # then and login manually to host, using e-mail as + # password. + $CPAN::Frontend->myprint(qq{Issuing "$CPAN::Config->{'ftp'}$verbose -n"\n}); + unshift( + @dialog, + "open $host", + "user anonymous $Config::Config{'cf_email'}" + ); + $self->talk_ftp("$CPAN::Config->{'ftp'}$verbose -n", @dialog); + ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, + $atime,$mtime,$ctime,$blksize,$blocks) = stat($aslocal); + $mtime ||= 0; + if ($mtime > $timestamp) { + $CPAN::Frontend->myprint("GOT $aslocal\n"); + $Thesite = $i; + return $aslocal; + } else { + $CPAN::Frontend->myprint("Bad luck... Still failed!\n"); } - $mess = qq{Either get }. - join(" or ",@mess). - qq{ or check, if the URL found in your configuration file, }. - $CPAN::Config->{urllist}[$i]. - qq{, is valid.}; - print Text::Wrap::wrap("","",$mess), "\n"; - } - print "Cannot fetch $file\n"; - if ($restore) { - rename "$aslocal.bak", $aslocal; - print "Trying to get away with old file:\n"; - print $self->ls($aslocal); - return $aslocal; + $CPAN::Frontend->myprint("Can't access URL $url.\n\n"); + sleep 2; } - return; +} + +sub talk_ftp { + my($self,$command,@dialog) = @_; + my $fh = FileHandle->new; + $fh->open("|$command") or die "Couldn't open ftp: $!"; + foreach (@dialog) { $fh->print("$_\n") } + $fh->close; # Wait for process to complete + my $wstatus = $?; + my $estatus = $wstatus >> 8; + $CPAN::Frontend->myprint(qq{ +Subprocess "|$command" + returned status $estatus (wstat $wstatus) +}) if $wstatus; + } # find2perl needs modularization, too, all the following is stolen @@ -1811,7 +2094,6 @@ sub new { my($t) = shift @tokens; if ($t eq "default"){ $hasdefault++; - # warn "saw a default entry before tokens[@tokens]"; last NETRC; } last TOKEN if $t eq "macdef"; @@ -1923,7 +2205,7 @@ sub cpl_option { CPAN->debug("word[$word] line[$line] pos[$pos]") if $CPAN::DEBUG; my(@ok) = qw(conf debug); return @ok if @words == 1; - return grep /^\Q$word\E/, @ok if @words == 2 && $word; + return grep /^\Q$word\E/, @ok if @words == 2 && length($word); if (0) { } elsif ($words[1] eq 'index') { return (); @@ -1948,34 +2230,38 @@ sub reload { my($cl,$force) = @_; my $time = time; - # XXX check if a newer one is available. (We currently read it from time to time) + # XXX check if a newer one is available. (We currently read it + # from time to time) for ($CPAN::Config->{index_expire}) { $_ = 0.001 unless $_ > 0.001; } - return if $last_time + $CPAN::Config->{index_expire}*86400 > $time; + return if $last_time + $CPAN::Config->{index_expire}*86400 > $time + and ! $force; my($debug,$t2); $last_time = $time; + my $needshort = $^O eq "dos"; + $cl->rd_authindex($cl->reload_x( - "authors/01mailrc.txt.gz", - "01mailrc.gz", - $force)); + "authors/01mailrc.txt.gz", + $needshort ? "01mailrc.gz" : "", + $force)); $t2 = time; $debug = "timing reading 01[".($t2 - $time)."]"; $time = $t2; return if $CPAN::Signal; # this is sometimes lengthy $cl->rd_modpacks($cl->reload_x( - "modules/02packages.details.txt.gz", - "02packag.gz", - $force)); + "modules/02packages.details.txt.gz", + $needshort ? "02packag.gz" : "", + $force)); $t2 = time; $debug .= "02[".($t2 - $time)."]"; $time = $t2; return if $CPAN::Signal; # this is sometimes lengthy $cl->rd_modlist($cl->reload_x( - "modules/03modlist.data.gz", - "03mlist.gz", - $force)); + "modules/03modlist.data.gz", + $needshort ? "03mlist.gz" : "", + $force)); $t2 = time; $debug .= "03[".($t2 - $time)."]"; $time = $t2; @@ -1985,24 +2271,23 @@ sub reload { #-> sub CPAN::Index::reload_x ; sub reload_x { my($cl,$wanted,$localname,$force) = @_; - $force ||= 0; + $force |= 2; # means we're dealing with an index here CPAN::Config->load; # we should guarantee loading wherever we rely # on Config XXX - my $abs_wanted = CPAN->catfile($CPAN::Config->{'keep_source_where'}, + $localname ||= $wanted; + my $abs_wanted = MM->catfile($CPAN::Config->{'keep_source_where'}, $localname); if ( -f $abs_wanted && -M $abs_wanted < $CPAN::Config->{'index_expire'} && - !$force + !($force & 1) ) { my $s = $CPAN::Config->{'index_expire'} == 1 ? "" : "s"; -# use Devel::Symdump; -# print Devel::Symdump->isa_tree, "\n"; $cl->debug(qq{$abs_wanted younger than $CPAN::Config->{'index_expire'} }. qq{day$s. I\'ll use that.}); return $abs_wanted; } else { - $force ||= 1; + $force |= 1; # means we're quite serious about it. } return CPAN::FTP->localize($wanted,$abs_wanted,$force); } @@ -2010,12 +2295,14 @@ sub reload_x { #-> sub CPAN::Index::rd_authindex ; sub rd_authindex { my($cl,$index_target) = @_; + return unless defined $index_target; my $pipe = "$CPAN::Config->{gzip} --decompress --stdout $index_target"; - print "Going to read $index_target\n"; + $CPAN::Frontend->myprint("Going to read $index_target\n"); my $fh = FileHandle->new("$pipe|"); while (<$fh>) { chomp; - my($userid,$fullname,$email) = /alias\s+(\S+)\s+\"([^\"\<]+)\s+<([^\>]+)\>\"/; + my($userid,$fullname,$email) = + /alias\s+(\S+)\s+\"([^\"\<]+)\s+<([^\>]+)\>\"/; next unless $userid && $fullname && $email; # instantiate an author object @@ -2030,8 +2317,9 @@ sub rd_authindex { #-> sub CPAN::Index::rd_modpacks ; sub rd_modpacks { my($cl,$index_target) = @_; + return unless defined $index_target; my $pipe = "$CPAN::Config->{gzip} --decompress --stdout $index_target"; - print "Going to read $index_target\n"; + $CPAN::Frontend->myprint("Going to read $index_target\n"); my $fh = FileHandle->new("$pipe|"); while (<$fh>) { last if /^\s*$/; @@ -2039,7 +2327,6 @@ sub rd_modpacks { while (<$fh>) { chomp; my($mod,$version,$dist) = split; -$dist = '' unless defined $dist; ### $version =~ s/^\+//; # if it as a bundle, instatiate a bundle object @@ -2048,16 +2335,16 @@ $dist = '' unless defined $dist; if ($mod eq 'CPAN') { local($^W)= 0; if ($version > $CPAN::VERSION){ - print qq{ + $CPAN::Frontend->myprint(qq{ There\'s a new CPAN.pm version (v$version) available! You might want to try install CPAN reload cpan - without quitting the current session. It should be a seemless upgrade + without quitting the current session. It should be a seamless upgrade while we are running... -}; +}); sleep 2; - print qq{\n}; + $CPAN::Frontend->myprint(qq{\n}); } last if $CPAN::Signal; } elsif ($mod =~ /^Bundle::(.*)/) { @@ -2066,16 +2353,19 @@ $dist = '' unless defined $dist; if ($bundle){ $id = $CPAN::META->instance('CPAN::Bundle',$mod); -### $id->set('CPAN_VERSION' => $version, 'CPAN_FILE' => $dist); + # Let's make it a module too, because bundles have so much + # in common with modules + $CPAN::META->instance('CPAN::Module',$mod); + # This "next" makes us faster but if the job is running long, we ignore # rereads which is bad. So we have to be a bit slower again. # } elsif ($CPAN::META->exists('CPAN::Module',$mod)) { # next; - } else { + + } + else { # instantiate a module object $id = $CPAN::META->instance('CPAN::Module',$mod); -### $id->set('CPAN_VERSION' => $version, 'CPAN_FILE' => $dist) -### if $id->cpan_version ne $version || $id->cpan_file ne $dist; # good speed in here } if ($id->cpan_file ne $dist){ @@ -2106,8 +2396,9 @@ $dist = '' unless defined $dist; #-> sub CPAN::Index::rd_modlist ; sub rd_modlist { my($cl,$index_target) = @_; + return unless defined $index_target; my $pipe = "$CPAN::Config->{gzip} --decompress --stdout $index_target"; - print "Going to read $index_target\n"; + $CPAN::Frontend->myprint("Going to read $index_target\n"); my $fh = FileHandle->new("$pipe|"); my $eval; while (<$fh>) { @@ -2224,11 +2515,11 @@ sub get { my @e; exists $self->{'build_dir'} and push @e, "Unwrapped into directory $self->{'build_dir'}"; - print join "", map {" $_\n"} @e and return if @e; + $CPAN::Frontend->myprint(join "", map {" $_\n"} @e) and return if @e; } my($local_file); my($local_wanted) = - CPAN->catfile( + MM->catfile( $CPAN::Config->{keep_source_where}, "authors", "id", @@ -2236,7 +2527,9 @@ sub get { ); $self->debug("Doing localize") if $CPAN::DEBUG; - $local_file = CPAN::FTP->localize("authors/id/$self->{ID}", $local_wanted); + $local_file = + CPAN::FTP->localize("authors/id/$self->{ID}", $local_wanted) + or $CPAN::Frontend->mydie("Giving up on '$local_wanted'\n"); $self->{localfile} = $local_file; my $builddir = $CPAN::META->{cachemgr}->dir; $self->debug("doing chdir $builddir") if $CPAN::DEBUG; @@ -2255,7 +2548,9 @@ sub get { mkdir "tmp", 0755 or Carp::croak "Couldn't mkdir tmp: $!"; chdir "tmp"; $self->debug("Changed directory to tmp") if $CPAN::DEBUG; - if ($local_file =~ /(\.tar\.(gz|Z)|\.tgz)$/i){ + if (! $local_file) { + Carp::croak "bad download, can't do anything :-(\n"; + } elsif ($local_file =~ /(\.tar\.(gz|Z)|\.tgz)$/i){ $self->untar_me($local_file); } elsif ( $local_file =~ /\.zip$/i ) { $self->unzip_me($local_file); @@ -2274,19 +2569,19 @@ sub get { my ($distdir,$packagedir); if (@readdir == 1 && -d $readdir[0]) { $distdir = $readdir[0]; - $packagedir = $CPAN::META->catdir($builddir,$distdir); - -d $packagedir and print "Removing previously used $packagedir\n"; + $packagedir = MM->catdir($builddir,$distdir); + -d $packagedir and $CPAN::Frontend->myprint("Removing previously used $packagedir\n"); File::Path::rmtree($packagedir); rename($distdir,$packagedir) or Carp::confess("Couldn't rename $distdir to $packagedir: $!"); } else { my $pragmatic_dir = $self->{'CPAN_USERID'} . '000'; $pragmatic_dir =~ s/\W_//g; $pragmatic_dir++ while -d "../$pragmatic_dir"; - $packagedir = $CPAN::META->catdir($builddir,$pragmatic_dir); + $packagedir = MM->catdir($builddir,$pragmatic_dir); File::Path::mkpath($packagedir); my($f); for $f (@readdir) { # is already without "." and ".." - my $to = $CPAN::META->catdir($packagedir,$f); + my $to = MM->catdir($packagedir,$f); rename($f,$to) or Carp::confess("Couldn't rename $f to $to: $!"); } } @@ -2297,12 +2592,12 @@ sub get { if $CPAN::DEBUG; File::Path::rmtree("tmp"); if ($CPAN::Config->{keep_source_where} =~ /^no/i ){ - print "Going to unlink $local_file\n"; + $CPAN::Frontend->myprint("Going to unlink $local_file\n"); unlink $local_file or Carp::carp "Couldn't unlink $local_file"; } - my($makefilepl) = $CPAN::META->catfile($packagedir,"Makefile.PL"); + my($makefilepl) = MM->catfile($packagedir,"Makefile.PL"); unless (-f $makefilepl) { - my($configure) = $CPAN::META->catfile($packagedir,"Configure"); + my($configure) = MM->catfile($packagedir,"Configure"); if (-f $configure) { # do we have anything to do? $self->{'configure'} = $configure; @@ -2319,8 +2614,8 @@ qq{# This Makefile.PL has been autogenerated by the module CPAN.pm WriteMakefile(NAME => q[$cf]); }); - print qq{Package comes without Makefile.PL.\n}. - qq{ Writing one on our own (calling it $cf)\n}; + $CPAN::Frontend->myprint(qq{Package comes without Makefile.PL.\n}. + qq{ Writing one on our own (calling it $cf)\n}); } } } @@ -2355,7 +2650,8 @@ sub pm2dir_me { $self->{archived} = "pm"; my $to = File::Basename::basename($local_file); $to =~ s/\.(gz|Z)$//; - my $system = "$CPAN::Config->{gzip} --decompress --stdout $local_file > $to"; + my $system = "$CPAN::Config->{gzip} --decompress --stdout ". + "$local_file > $to"; if (system($system) == 0) { $self->{unwrapped} = "YES"; } else { @@ -2377,14 +2673,14 @@ sub new { sub look { my($self) = @_; if ( $CPAN::Config->{'shell'} ) { - print qq{ + $CPAN::Frontend->myprint(qq{ Trying to open a subshell in the build directory... -}; +}); } else { - print qq{ + $CPAN::Frontend->myprint(qq{ Your configuration does not define a value for subshells. Please define it with "o conf shell " -}; +}); return; } my $dist = $self->id; @@ -2394,8 +2690,9 @@ Please define it with "o conf shell " $getcwd = $CPAN::Config->{'getcwd'} || 'cwd'; my $pwd = CPAN->$getcwd(); chdir($dir); - print qq{Working directory is $dir.\n}; - system($CPAN::Config->{'shell'}) == 0 or die "Subprocess shell error"; + $CPAN::Frontend->myprint(qq{Working directory is $dir\n}); + system($CPAN::Config->{'shell'}) == 0 + or $CPAN::Frontend->mydie("Subprocess shell error"); chdir($pwd); } @@ -2407,19 +2704,29 @@ sub readme { $self->debug("sans[$sans] suffix[$suffix]\n") if $CPAN::DEBUG; my($local_file); my($local_wanted) = - CPAN->catfile( + MM->catfile( $CPAN::Config->{keep_source_where}, "authors", "id", split("/","$sans.readme"), ); $self->debug("Doing localize") if $CPAN::DEBUG; - $local_file = CPAN::FTP->localize("authors/id/$sans.readme", $local_wanted); + $local_file = CPAN::FTP->localize("authors/id/$sans.readme", + $local_wanted) + or $CPAN::Frontend->mydie(qq{No $sans.readme found});; my $fh_pager = FileHandle->new; + local($SIG{PIPE}) = "IGNORE"; $fh_pager->open("|$CPAN::Config->{'pager'}") or die "Could not open pager $CPAN::Config->{'pager'}: $!"; my $fh_readme = FileHandle->new; - $fh_readme->open($local_file) or die "Could not open $local_file: $!"; + $fh_readme->open($local_file) + or $CPAN::Frontend->mydie(qq{Could not open "$local_file": $!}); + $CPAN::Frontend->myprint(qq{ +Displaying file + $local_file +with pager "$CPAN::Config->{'pager'}" +}); + sleep 2; $fh_pager->print(<$fh_readme>); } @@ -2430,32 +2737,36 @@ sub verifyMD5 { my @e; $self->{MD5_STATUS} ||= ""; $self->{MD5_STATUS} eq "OK" and push @e, "MD5 Checksum was ok"; - print join "", map {" $_\n"} @e and return if @e; + $CPAN::Frontend->myprint(join "", map {" $_\n"} @e) and return if @e; } my($lc_want,$lc_file,@local,$basename); @local = split("/",$self->{ID}); pop @local; push @local, "CHECKSUMS"; $lc_want = - CPAN->catfile($CPAN::Config->{keep_source_where}, + MM->catfile($CPAN::Config->{keep_source_where}, "authors", "id", @local); local($") = "/"; if ( - -f $lc_want + -s $lc_want && $self->MD5_check_file($lc_want) ) { return $self->{MD5_STATUS} = "OK"; } $lc_file = CPAN::FTP->localize("authors/id/@local", - $lc_want,'force>:-{'); + $lc_want,1); unless ($lc_file) { $local[-1] .= ".gz"; $lc_file = CPAN::FTP->localize("authors/id/@local", - "$lc_want.gz",'force>:-{'); - my @system = ($CPAN::Config->{gzip}, '--decompress', $lc_file); - system(@system) == 0 or die "Could not uncompress $lc_file"; - $lc_file =~ s/\.gz$//; + "$lc_want.gz",1); + if ($lc_file) { + my @system = ($CPAN::Config->{gzip}, '--decompress', $lc_file); + system(@system) == 0 or die "Could not uncompress $lc_file"; + $lc_file =~ s/\.gz$//; + } else { + return; + } } $self->MD5_check_file($lc_file); } @@ -2464,11 +2775,11 @@ sub verifyMD5 { sub MD5_check_file { my($self,$chk_file) = @_; my($cksum,$file,$basename); - $file = $self->{localfile}; + $file = $self->{localfile}; $basename = File::Basename::basename($file); my $fh = FileHandle->new; - local($/); if (open $fh, $chk_file){ + local($/); my $eval = <$fh>; close $fh; my($comp) = Safe->new(); @@ -2494,22 +2805,23 @@ sub MD5_check_file { binmode $fh && $self->eq_MD5($fh,$cksum->{$basename}->{'md5-ungz'}) ){ - print "Checksum for $file ok\n"; + $CPAN::Frontend->myprint("Checksum for $file ok\n"); return $self->{MD5_STATUS} = "OK"; } else { - print qq{Checksum mismatch for distribution file. }. - qq{Please investigate.\n\n}; - print $self->as_string; - print $CPAN::META->instance( - 'CPAN::Author', - $self->{CPAN_USERID} - )->as_string; + $CPAN::Frontend->myprint(qq{Checksum mismatch for }. + qq{distribution file. }. + qq{Please investigate.\n\n}. + $self->as_string, + $CPAN::META->instance( + 'CPAN::Author', + $self->{CPAN_USERID} + )->as_string); my $wrap = qq{I\'d recommend removing $file. It seems to be a bogus file. Maybe you have configured your \`urllist\' with a bad URL. Please check this array with \`o conf urllist\', and retry.}; - print Text::Wrap::wrap("","",$wrap); - print "\n\n"; + $CPAN::Frontend->myprint(Text::Wrap::wrap("","",$wrap)); + $CPAN::Frontend->myprint("\n\n"); sleep 3; return; } @@ -2517,9 +2829,11 @@ retry.}; } else { $self->{MD5_STATUS} ||= ""; if ($self->{MD5_STATUS} eq "NIL") { - print "\nNo md5 checksum for $basename in local $chk_file."; - print "Removing $chk_file\n"; - unlink $chk_file or print "Could not unlink: $!"; + $CPAN::Frontend->myprint(qq{ +No md5 checksum for $basename in local $chk_file. +Removing $chk_file +}); + unlink $chk_file or $CPAN::Frontend->myprint("Could not unlink: $!"); sleep 1; } $self->{MD5_STATUS} = "NIL"; @@ -2556,12 +2870,13 @@ sub perl { my($perl) = MM->file_name_is_absolute($^X) ? $^X : ""; my $getcwd = $CPAN::Config->{'getcwd'} || 'cwd'; my $pwd = CPAN->$getcwd(); - my $candidate = $CPAN::META->catfile($pwd,$^X); + my $candidate = MM->catfile($pwd,$^X); $perl ||= $candidate if MM->maybe_command($candidate); unless ($perl) { my ($component,$perl_name); DIST_PERLNAME: foreach $perl_name ($^X, 'perl', 'perl5', "perl$]") { - PATH_COMPONENT: foreach $component (MM->path(), $Config::Config{'binexp'}) { + PATH_COMPONENT: foreach $component (MM->path(), + $Config::Config{'binexp'}) { next unless defined($component) && $component; my($abs) = MM->catfile($component,$perl_name); if (MM->maybe_command($abs)) { @@ -2577,8 +2892,7 @@ sub perl { #-> sub CPAN::Distribution::make ; sub make { my($self) = @_; - $self->debug($self->id) if $CPAN::DEBUG; - print "Running make\n"; + $CPAN::Frontend->myprint(sprintf "Running make for %s\n", $self->id); $self->get; EXCUSE: { my @e; @@ -2595,9 +2909,9 @@ sub make { defined $self->{'make'} and push @e, "Has already been processed within this session"; - print join "", map {" $_\n"} @e and return if @e; + $CPAN::Frontend->myprint(join "", map {" $_\n"} @e) and return if @e; } - print "\n CPAN.pm: Going to build ".$self->id."\n\n"; + $CPAN::Frontend->myprint("\n CPAN.pm: Going to build ".$self->id."\n\n"); my $builddir = $self->dir; chdir $builddir or Carp::croak("Couldn't chdir $builddir: $!"); $self->debug("Changed directory to $builddir") if $CPAN::DEBUG; @@ -2629,7 +2943,7 @@ sub make { exec $system; } } else { - print "Cannot fork: $!"; + $CPAN::Frontend->myprint("Cannot fork: $!"); return; } }; @@ -2637,7 +2951,7 @@ sub make { if ($@){ kill 9, $pid; waitpid $pid, 0; - print $@; + $CPAN::Frontend->myprint($@); $self->{writemakefile} = "NO - $@"; $@ = ""; return; @@ -2654,12 +2968,12 @@ sub make { return if $CPAN::Signal; $system = join " ", $CPAN::Config->{'make'}, $CPAN::Config->{make_arg}; if (system($system) == 0) { - print " $system -- OK\n"; + $CPAN::Frontend->myprint(" $system -- OK\n"); $self->{'make'} = "YES"; } else { $self->{writemakefile} = "YES"; $self->{'make'} = "NO"; - print " $system -- NOT OK\n"; + $CPAN::Frontend->myprint(" $system -- NOT OK\n"); } } @@ -2668,7 +2982,7 @@ sub test { my($self) = @_; $self->make; return if $CPAN::Signal; - print "Running make test\n"; + $CPAN::Frontend->myprint("Running make test\n"); EXCUSE: { my @e; exists $self->{'make'} or push @e, @@ -2679,34 +2993,37 @@ sub test { push @e, "Oops, make had returned bad status"; exists $self->{'build_dir'} or push @e, "Has no own directory"; - print join "", map {" $_\n"} @e and return if @e; + $CPAN::Frontend->myprint(join "", map {" $_\n"} @e) and return if @e; } - chdir $self->{'build_dir'} or Carp::croak("Couldn't chdir to $self->{'build_dir'}"); - $self->debug("Changed directory to $self->{'build_dir'}") if $CPAN::DEBUG; + chdir $self->{'build_dir'} or + Carp::croak("Couldn't chdir to $self->{'build_dir'}"); + $self->debug("Changed directory to $self->{'build_dir'}") + if $CPAN::DEBUG; my $system = join " ", $CPAN::Config->{'make'}, "test"; if (system($system) == 0) { - print " $system -- OK\n"; + $CPAN::Frontend->myprint(" $system -- OK\n"); $self->{'make_test'} = "YES"; } else { $self->{'make_test'} = "NO"; - print " $system -- NOT OK\n"; + $CPAN::Frontend->myprint(" $system -- NOT OK\n"); } } #-> sub CPAN::Distribution::clean ; sub clean { my($self) = @_; - print "Running make clean\n"; + $CPAN::Frontend->myprint("Running make clean\n"); EXCUSE: { my @e; exists $self->{'build_dir'} or push @e, "Has no own directory"; - print join "", map {" $_\n"} @e and return if @e; + $CPAN::Frontend->myprint(join "", map {" $_\n"} @e) and return if @e; } - chdir $self->{'build_dir'} or Carp::croak("Couldn't chdir to $self->{'build_dir'}"); + chdir $self->{'build_dir'} or + Carp::croak("Couldn't chdir to $self->{'build_dir'}"); $self->debug("Changed directory to $self->{'build_dir'}") if $CPAN::DEBUG; my $system = join " ", $CPAN::Config->{'make'}, "clean"; if (system($system) == 0) { - print " $system -- OK\n"; + $CPAN::Frontend->myprint(" $system -- OK\n"); $self->force; } else { # Hmmm, what to do if make clean failed? @@ -2718,7 +3035,7 @@ sub install { my($self) = @_; $self->test; return if $CPAN::Signal; - print "Running make install\n"; + $CPAN::Frontend->myprint("Running make install\n"); EXCUSE: { my @e; exists $self->{'build_dir'} or push @e, "Has no own directory"; @@ -2730,7 +3047,8 @@ sub install { $self->{'make'} eq 'NO' and push @e, "Oops, make had returned bad status"; - push @e, "make test had returned bad status, won't install without force" + push @e, "make test had returned bad status, ". + "won't install without force" if exists $self->{'make_test'} and $self->{'make_test'} eq 'NO' and ! $self->{'force_update'}; @@ -2739,26 +3057,30 @@ sub install { $self->{'install'} eq "YES" ? "Already done" : "Already tried without success"; - print join "", map {" $_\n"} @e and return if @e; + $CPAN::Frontend->myprint(join "", map {" $_\n"} @e) and return if @e; } - chdir $self->{'build_dir'} or Carp::croak("Couldn't chdir to $self->{'build_dir'}"); - $self->debug("Changed directory to $self->{'build_dir'}") if $CPAN::DEBUG; - my $system = join " ", $CPAN::Config->{'make'}, "install", $CPAN::Config->{make_install_arg}; + chdir $self->{'build_dir'} or + Carp::croak("Couldn't chdir to $self->{'build_dir'}"); + $self->debug("Changed directory to $self->{'build_dir'}") + if $CPAN::DEBUG; + my $system = join(" ", $CPAN::Config->{'make'}, + "install", $CPAN::Config->{make_install_arg}); my($pipe) = FileHandle->new("$system 2>&1 |"); my($makeout) = ""; while (<$pipe>){ - print; + $CPAN::Frontend->myprint($_); $makeout .= $_; } $pipe->close; if ($?==0) { - print " $system -- OK\n"; + $CPAN::Frontend->myprint(" $system -- OK\n"); $self->{'install'} = "YES"; } else { $self->{'install'} = "NO"; - print " $system -- NOT OK\n"; + $CPAN::Frontend->myprint(" $system -- NOT OK\n"); if ($makeout =~ /permission/s && $> > 0) { - print " You may have to su to root to install the package\n"; + $CPAN::Frontend->myprint(qq{ You may have to su }. + qq{to root to install the package\n}); } } } @@ -2782,19 +3104,26 @@ sub as_string { sub contains { my($self) = @_; my($parsefile) = $self->inst_file; + my($id) = $self->id; + $self->debug("parsefile[$parsefile]id[$id]") if $CPAN::DEBUG; unless ($parsefile) { # Try to get at it in the cpan directory $self->debug("no parsefile") if $CPAN::DEBUG; - my $dist = $CPAN::META->instance('CPAN::Distribution',$self->{'CPAN_FILE'}); + Carp::confess "I don't know a $id" unless $self->{CPAN_FILE}; + my $dist = $CPAN::META->instance('CPAN::Distribution', + $self->{CPAN_FILE}); $dist->get; $self->debug($dist->as_string) if $CPAN::DEBUG; - my($todir) = $CPAN::META->catdir($CPAN::Config->{'cpan_home'},"Bundle"); - File::Path::mkpath($todir); - my($me,$from,$to); - ($me = $self->id) =~ s/.*://; - $from = $self->find_bundle_file($dist->{'build_dir'},"$me.pm"); - $to = $CPAN::META->catfile($todir,"$me.pm"); - File::Copy::copy($from, $to) or Carp::confess("Couldn't copy $from to $to: $!"); + my($todir) = $CPAN::Config->{'cpan_home'}; + my(@me,$from,$to,$me); + @me = split /::/, $self->id; + $me[-1] .= ".pm"; + $me = MM->catfile(@me); + $from = $self->find_bundle_file($dist->{'build_dir'},$me); + $to = MM->catfile($todir,$me); + File::Path::mkpath(File::Basename::dirname($to)); + File::Copy::copy($from, $to) + or Carp::confess("Couldn't copy $from to $to: $!"); $parsefile = $to; } my @result; @@ -2804,7 +3133,8 @@ sub contains { my $inpod = 0; $self->debug("parsefile[$parsefile]") if $CPAN::DEBUG; while (<$fh>) { - $inpod = /^=(?!head1\s+CONTENTS)/ ? 0 : /^=head1\s+CONTENTS/ ? 1 : $inpod; + $inpod = /^=(?!head1\s+CONTENTS)/ ? 0 : + /^=head1\s+CONTENTS/ ? 1 : $inpod; next unless $inpod; next if /^=/; next if /^\s+$/; @@ -2821,9 +3151,10 @@ sub contains { #-> sub CPAN::Bundle::find_bundle_file sub find_bundle_file { my($self,$where,$what) = @_; - my $bu = $CPAN::META->catfile($where,$what); + $self->debug("where[$where]what[$what]") if $CPAN::DEBUG; + my $bu = MM->catfile($where,$what); return $bu if -f $bu; - my $manifest = $CPAN::META->catfile($where,"MANIFEST"); + my $manifest = MM->catfile($where,"MANIFEST"); unless (-f $manifest) { require ExtUtils::Manifest; my $getcwd = $CPAN::Config->{'getcwd'} || 'cwd'; @@ -2832,17 +3163,24 @@ sub find_bundle_file { ExtUtils::Manifest::mkmanifest(); chdir $cwd; } - my $fh = FileHandle->new($manifest) or Carp::croak("Couldn't open $manifest: $!"); + my $fh = FileHandle->new($manifest) + or Carp::croak("Couldn't open $manifest: $!"); local($/) = "\n"; while (<$fh>) { next if /^\s*\#/; my($file) = /(\S+)/; - if ($file =~ m|Bundle/$what$|) { + if ($file =~ m|\Q$what\E$|) { $bu = $file; - return $CPAN::META->catfile($where,$bu); + return MM->catfile($where,$bu); + } elsif ($what =~ s|Bundle/||) { # retry if she managed to + # have no Bundle directory + if ($file =~ m|\Q$what\E$|) { + $bu = $file; + return MM->catfile($where,$bu); + } } } - Carp::croak("Could't find a Bundle file in $where"); + Carp::croak("Couldn't find a Bundle file in $where"); } #-> sub CPAN::Bundle::inst_file ; @@ -2850,7 +3188,12 @@ sub inst_file { my($self) = @_; my($me,$inst_file); ($me = $self->id) =~ s/.*://; - $inst_file = $CPAN::META->catfile($CPAN::Config->{'cpan_home'},"Bundle", "$me.pm"); +## my(@me,$inst_file); +## @me = split /::/, $self->id; +## $me[-1] .= ".pm"; + $inst_file = MM->catfile($CPAN::Config->{'cpan_home'}, + "Bundle", "$me.pm"); +## "Bundle", @me); return $self->{'INST_FILE'} = $inst_file if -f $inst_file; # $inst_file = $self->SUPER::inst_file; @@ -2862,15 +3205,18 @@ sub inst_file { sub rematein { my($self,$meth) = @_; $self->debug("self[$self] meth[$meth]") if $CPAN::DEBUG; + my($id) = $self->id; + Carp::croak "Can't $meth $id, don't have an associated bundle file. :-(\n" + unless $self->inst_file || $self->{CPAN_FILE}; my($s); for $s ($self->contains) { my($type) = $s =~ m|/| ? 'CPAN::Distribution' : $s =~ m|^Bundle::| ? 'CPAN::Bundle' : 'CPAN::Module'; if ($type eq 'CPAN::Distribution') { - warn qq{ + $CPAN::Frontend->mywarn(qq{ The Bundle }.$self->id.qq{ contains explicitly a file $s. -}; +}); sleep 3; } $CPAN::META->instance($type,$s)->$meth(); @@ -2900,7 +3246,8 @@ sub clean { shift->rematein('clean',@_); } #-> sub CPAN::Bundle::readme ; sub readme { my($self) = @_; - my($file) = $self->cpan_file or print("No File found for bundle ", $self->id, "\n"), return; + my($file) = $self->cpan_file or $CPAN::Frontend->myprint(qq{ +No File found for bundle } . $self->id . qq{\n}), return; $self->debug("self[$self] file[$file]") if $CPAN::DEBUG; $CPAN::META->instance('CPAN::Distribution',$file)->readme; } @@ -2913,7 +3260,8 @@ sub as_glimpse { my(@m); my $class = ref($self); $class =~ s/^CPAN:://; - push @m, sprintf "%-15s %-15s (%s)\n", $class, $self->{ID}, $self->cpan_file; + push @m, sprintf("%-15s %-15s (%s)\n", $class, $self->{ID}, + $self->cpan_file); join "", @m; } @@ -2927,25 +3275,34 @@ sub as_string { local($^W) = 0; push @m, $class, " id = $self->{ID}\n"; my $sprintf = " %-12s %s\n"; - push @m, sprintf $sprintf, 'DESCRIPTION', $self->{description} if $self->{description}; + push @m, sprintf($sprintf, 'DESCRIPTION', $self->{description}) + if $self->{description}; my $sprintf2 = " %-12s %s (%s)\n"; my($userid); if ($userid = $self->{'CPAN_USERID'} || $self->{'userid'}){ - push @m, sprintf( - $sprintf2, - 'CPAN_USERID', - $userid, - CPAN::Shell->expand('Author',$userid)->fullname - ) - } - push @m, sprintf $sprintf, 'CPAN_VERSION', $self->{CPAN_VERSION} if $self->{CPAN_VERSION}; - push @m, sprintf $sprintf, 'CPAN_FILE', $self->{CPAN_FILE} if $self->{CPAN_FILE}; + my $author; + if ($author = CPAN::Shell->expand('Author',$userid)) { + push @m, sprintf( + $sprintf2, + 'CPAN_USERID', + $userid, + $author->fullname + ); + } + } + push @m, sprintf($sprintf, 'CPAN_VERSION', $self->{CPAN_VERSION}) + if $self->{CPAN_VERSION}; + push @m, sprintf($sprintf, 'CPAN_FILE', $self->{CPAN_FILE}) + if $self->{CPAN_FILE}; my $sprintf3 = " %-12s %1s%1s%1s%1s (%s,%s,%s,%s)\n"; my(%statd,%stats,%statl,%stati); - @statd{qw,? i c a b R M S,} = qw,unknown idea pre-alpha alpha beta released mature standard,; - @stats{qw,? m d u n,} = qw,unknown mailing-list developer comp.lang.perl.* none,; + @statd{qw,? i c a b R M S,} = qw,unknown idea + pre-alpha alpha beta released mature standard,; + @stats{qw,? m d u n,} = qw,unknown mailing-list + developer comp.lang.perl.* none,; @statl{qw,? p c + o,} = qw,unknown perl C C++ other,; - @stati{qw,? f r O,} = qw,unknown functions references+ties object-oriented,; + @stati{qw,? f r O,} = qw,unknown functions + references+ties object-oriented,; $statd{' '} = 'unknown'; $stats{' '} = 'unknown'; $statl{' '} = 'unknown'; @@ -2964,12 +3321,14 @@ sub as_string { ) if $self->{statd}; my $local_file = $self->inst_file; if ($local_file && ! exists $self->{MANPAGE}) { - my $fh = FileHandle->new($local_file) or Carp::croak("Couldn't open $local_file: $!"); + my $fh = FileHandle->new($local_file) + or Carp::croak("Couldn't open $local_file: $!"); my $inpod = 0; my(@result); local $/ = "\n"; while (<$fh>) { - $inpod = /^=(?!head1\s+NAME)/ ? 0 : /^=head1\s+NAME/ ? 1 : $inpod; + $inpod = /^=(?!head1\s+NAME)/ ? 0 : + /^=head1\s+NAME/ ? 1 : $inpod; next unless $inpod; next if /^=/; next if /^\s+$/; @@ -2981,10 +3340,13 @@ sub as_string { } my($item); for $item (qw/MANPAGE CONTAINS/) { - push @m, sprintf $sprintf, $item, $self->{$item} if exists $self->{$item}; + push @m, sprintf($sprintf, $item, $self->{$item}) + if exists $self->{$item}; } - push @m, sprintf $sprintf, 'INST_FILE', $local_file || "(not installed)"; - push @m, sprintf $sprintf, 'INST_VERSION', $self->inst_version if $local_file; + push @m, sprintf($sprintf, 'INST_FILE', + $local_file || "(not installed)"); + push @m, sprintf($sprintf, 'INST_VERSION', + $self->inst_version) if $local_file; join "", @m, "\n"; } @@ -2995,10 +3357,17 @@ sub cpan_file { unless (defined $self->{'CPAN_FILE'}) { CPAN::Index->reload; } - if (defined $self->{'CPAN_FILE'}){ + if (exists $self->{'CPAN_FILE'} && defined $self->{'CPAN_FILE'}){ return $self->{'CPAN_FILE'}; - } elsif (defined $self->{'userid'}) { - return "Contact Author ".$self->{'userid'}."=".$CPAN::META->instance(CPAN::Author,$self->{'userid'})->fullname + } elsif (exists $self->{'userid'} && defined $self->{'userid'}) { + my $fullname = $CPAN::META->instance(CPAN::Author, + $self->{'userid'})->fullname; + unless (defined $fullname) { + $CPAN::Frontend->mywarn(qq{Full name of author }. + qq{$self->{userid} not known}); + return "Contact Author $self->{userid}"; + } + return "Contact Author $self->{userid} ($fullname)" } else { return "N/A"; } @@ -3007,7 +3376,20 @@ sub cpan_file { *name = \&cpan_file; #-> sub CPAN::Module::cpan_version ; -sub cpan_version { shift->{'CPAN_VERSION'} } +sub cpan_version { + my $self = shift; + $self->{'CPAN_VERSION'} = 'undef' + unless defined $self->{'CPAN_VERSION'}; # I believe this is + # always a bug in the + # index and should be + # reported as such, + # but usually I find + # out such an error + # and do not want to + # provoke too many + # bugreports + $self->{'CPAN_VERSION'}; +} #-> sub CPAN::Module::force ; sub force { @@ -3053,8 +3435,13 @@ sub install { if (1){ # A block for scoping $^W, the if is just for the visual # appeal local($^W)=0; - if ($inst_file && $have >= $latest && not exists $self->{'force_update'}) { - print $self->id, " is up to date.\n"; + if ($inst_file + && + $have >= $latest + && + not exists $self->{'force_update'} + ) { + $CPAN::Frontend->myprint( $self->id. " is up to date.\n"); } else { $doit = 1; } @@ -3071,7 +3458,7 @@ sub inst_file { @packpath = split /::/, $self->{ID}; $packpath[-1] .= ".pm"; foreach $dir (@INC) { - my $pmfile = CPAN->catfile($dir,@packpath); + my $pmfile = MM->catfile($dir,@packpath); if (-f $pmfile){ return $pmfile; } @@ -3087,7 +3474,7 @@ sub xs_file { push @packpath, $packpath[-1]; $packpath[-1] .= "." . $Config::Config{'dlext'}; foreach $dir (@INC) { - my $xsfile = CPAN->catfile($dir,'auto',@packpath); + my $xsfile = MM->catfile($dir,'auto',@packpath); if (-f $xsfile){ return $xsfile; } @@ -3098,12 +3485,10 @@ sub xs_file { #-> sub CPAN::Module::inst_version ; sub inst_version { my($self) = @_; - my $parsefile = $self->inst_file or return 0; + my $parsefile = $self->inst_file or return; local($^W) = 0 if $] < 5.00303 && $ExtUtils::MakeMaker::VERSION < 5.38; - my $have = MM->parse_version($parsefile); - $have ||= 0; + my $have = MM->parse_version($parsefile) || "undef"; $have =~ s/\s+//g; - $have ||= 0; $have; } @@ -3257,7 +3642,8 @@ the package CPAN::Shell. If you enter the shell command, all your input is split by the Text::ParseWords::shellwords() routine which acts like most shells do. The first word is being interpreted as the method to be called and the rest of the words are treated as arguments -to this method. +to this method. Continuation lines are supported if a line ends with a +literal backslash. =head2 autobundle @@ -3287,7 +3673,7 @@ perl breaks binary compatibility. If one of the modules that CPAN uses is in turn depending on binary compatibility (so you cannot run CPAN commands), then you should try the CPAN::Nox module for recovery. -=head2 The 4 C Classes: Author, Bundle, Module, Distribution +=head2 The four C Classes: Author, Bundle, Module, Distribution Although it may be considered internal, the class hierarchie does matter for both users and programmer. CPAN.pm deals with above @@ -3318,12 +3704,12 @@ BAR/Foo-1.23.tar.gz) with all accompanying material in there. But if you would like to install version 1.23_90, you need to know where the distribution file resides on CPAN relative to the authors/id/ directory. If the author is BAR, this might be BAR/Foo-1.23_90.tar.gz, -so he would have to say +so you would have to say install BAR/Foo-1.23_90.tar.gz The first example will be driven by an object of the class -CPAN::Module, the second by an object of class Distribution. +CPAN::Module, the second by an object of class CPAN::Distribution. =head2 ProgrammerE<39>s interface @@ -3365,7 +3751,8 @@ functionalities that are available in the shell. # list all modules on my disk that have no VERSION number for $mod (CPAN::Shell->expand("Module","/./")){ next unless $mod->inst_file; - next if $mod->inst_version; + # MakeMaker convention for undefined $VERSION: + next unless $mod->inst_version eq "undef"; print "No VERSION in ", $mod->id, "\n"; } @@ -3423,10 +3810,6 @@ your @INC path. The autobundle() command which is available in the shell interface does that for you by including all currently installed modules in a snapshot bundle file. -There is a meaningless Bundle::Demo available on CPAN. Try to install -it, it usually does no harm, just demonstrates what the Bundle -interface looks like. - =head2 Prerequisites If you have a local mirror of CPAN and can access all files with @@ -3550,6 +3933,21 @@ works like the corresponding perl commands. =back +=head2 CD-ROM support + +The C parameter of the configuration table contains a list of +URLs that are to be used for downloading. If the list contains any +C URLs, CPAN always tries to get files from there first. This +feature is disabled for index files. So the recommendation for the +owner of a CD-ROM with CPAN contents is: include your local, possibly +outdated CD-ROM as a C URL at the end of urllist, e.g. + + o conf urllist push file://localhost/CDROM/CPAN + +CPAN.pm will then fetch the index files from one of the CPAN sites +that come at the beginning of urllist. It will later check for each +module if there is a local copy of the most recent version. + =head1 SECURITY There's no strong security layer in CPAN.pm. CPAN.pm helps you to @@ -3568,11 +3966,11 @@ oneliners. =head1 BUGS we should give coverage for _all_ of the CPAN and not just the -__PAUSE__ part, right? In this discussion CPAN and PAUSE have become +PAUSE part, right? In this discussion CPAN and PAUSE have become equal -- but they are not. PAUSE is authors/ and modules/. CPAN is PAUSE plus the clpa/, doc/, misc/, ports/, src/, scripts/. -Future development should be directed towards a better intergration of +Future development should be directed towards a better integration of the other parts. =head1 AUTHOR diff --git a/lib/CPAN/FirstTime.pm b/lib/CPAN/FirstTime.pm index 3e572d6..3fa21c6 100644 --- a/lib/CPAN/FirstTime.pm +++ b/lib/CPAN/FirstTime.pm @@ -15,7 +15,7 @@ use ExtUtils::MakeMaker qw(prompt); use FileHandle (); use File::Path (); use vars qw($VERSION); -$VERSION = substr q$Revision: 1.20 $, 10; +$VERSION = substr q$Revision: 1.21 $, 10; =head1 NAME @@ -210,7 +210,7 @@ the default and recommended setting. if (@{$CPAN::Config->{urllist}||[]}) { print qq{ I found a list of URLs in CPAN::Config and will use this. -You can change it later with the 'o conf' command. +You can change it later with the 'o conf urllist' command. } } elsif ( diff --git a/lib/Carp.pm b/lib/Carp.pm index 351f83b..685a793 100644 --- a/lib/Carp.pm +++ b/lib/Carp.pm @@ -53,7 +53,7 @@ $MaxArgLen = 64; # How much of each argument to print. 0 = all. $MaxArgNums = 8; # How many arguments to print. 0 = all. require Exporter; -@ISA = Exporter; +@ISA = ('Exporter'); @EXPORT = qw(confess croak carp); @EXPORT_OK = qw(cluck verbose); @EXPORT_FAIL = qw(verbose); # hook to enable verbose mode diff --git a/lib/Cwd.pm b/lib/Cwd.pm index efcfeca..3bd0085 100644 --- a/lib/Cwd.pm +++ b/lib/Cwd.pm @@ -26,14 +26,22 @@ The getcwd() function re-implements the getcwd(3) (or getwd(3)) functions in Perl. The fastcwd() function looks the same as getcwd(), but runs faster. -It's also more dangerous because you might conceivably chdir() out of a -directory that you can't chdir() back into. +It's also more dangerous because it might conceivably chdir() you out +of a directory that it can't chdir() you back into. If fastcwd +encounters a problem it will return undef but will probably leave you +in a different directory. For a measure of extra security, if +everything appears to have worked, the fastcwd() function will check +that it leaves you in the same directory that it started in. If it has +changed it will C with the message "Unstable directory path, +current directory changed unexpectedly". That should never happen. The cwd() function looks the same as getcwd and fastgetcwd but is implemented using the most natural and safe form for the current architecture. For most systems it is identical to `pwd` (but without -the trailing line terminator). It is recommended that cwd (or another -*cwd() function) is used in I code to ensure portability. +the trailing line terminator). + +It is recommended that cwd (or another *cwd() function) is used in +I code to ensure portability. If you ask to override your chdir() built-in function, then your PWD environment variable will be kept up to date. (See @@ -101,7 +109,7 @@ sub getcwd } if ($pst[0] == $cst[0] && $pst[1] == $cst[1]) { - $dir = ''; + $dir = undef; } else { @@ -125,9 +133,9 @@ sub getcwd while ($dir eq '.' || $dir eq '..' || $tst[0] != $pst[0] || $tst[1] != $pst[1]); } - $cwd = "$dir/$cwd"; + $cwd = (defined $dir ? "$dir" : "" ) . "/$cwd" ; closedir(PARENT); - } while ($dir); + } while (defined $dir); chop($cwd) unless $cwd eq '/'; # drop the trailing / $cwd; } @@ -140,33 +148,45 @@ sub getcwd # # This is a faster version of getcwd. It's also more dangerous because # you might chdir out of a directory that you can't chdir back into. + +# List of metachars taken from do_exec() in doio.c +my $quoted_shell_meta = quotemeta('$&*(){}[]";\\|?<>~`'."'\n"); sub fastcwd { my($odev, $oino, $cdev, $cino, $tdev, $tino); my(@path, $path); local(*DIR); - ($cdev, $cino) = stat('.'); + my($orig_cdev, $orig_cino) = stat('.'); + ($cdev, $cino) = ($orig_cdev, $orig_cino); for (;;) { my $direntry; ($odev, $oino) = ($cdev, $cino); - chdir('..'); + chdir('..') || return undef; ($cdev, $cino) = stat('.'); last if $odev == $cdev && $oino == $cino; - opendir(DIR, '.'); + opendir(DIR, '.') || return undef; for (;;) { $direntry = readdir(DIR); + last unless defined $direntry; next if $direntry eq '.'; next if $direntry eq '..'; - last unless defined $direntry; ($tdev, $tino) = lstat($direntry); last unless $tdev != $odev || $tino != $oino; } closedir(DIR); + return undef unless defined $direntry; # should never happen unshift(@path, $direntry); } - chdir($path = '/' . join('/', @path)); + $path = '/' . join('/', @path); + # At this point $path may be tainted (if tainting) and chdir would fail. + # To be more useful we untaint it then check that we landed where we started. + $path = $1 if $path =~ /^(.*)$/; # untaint + chdir($path) || return undef; + ($cdev, $cino) = stat('.'); + die "Unstable directory path, current directory changed unexpectedly" + if $cdev != $orig_cdev || $cino != $orig_cino; $path; } diff --git a/lib/English.pm b/lib/English.pm index 0cf62bd..bbb6bd7 100644 --- a/lib/English.pm +++ b/lib/English.pm @@ -92,7 +92,7 @@ sub import { *OSNAME ); -# The ground of all being. +# The ground of all being. @ARG is deprecated (5.005 makes @_ lexical) *ARG = *_ ; diff --git a/lib/ExtUtils/Install.pm b/lib/ExtUtils/Install.pm index ff5dbf1..4400858 100644 --- a/lib/ExtUtils/Install.pm +++ b/lib/ExtUtils/Install.pm @@ -34,6 +34,7 @@ sub install { use File::Copy qw(copy); use File::Find qw(find); use File::Path qw(mkpath); + use File::Compare qw(compare); my(%hash) = %$hash; my(%pack, %write, $dir, $warn_permissions); @@ -96,7 +97,7 @@ sub install { my $diff = 0; if ( -f $targetfile && -s _ == $size) { # We have a good chance, we can skip this one - $diff = my_cmp($_,$targetfile); + $diff = compare($_,$targetfile); } else { print "$_ differs\n" if $verbose>1; $diff++; @@ -166,32 +167,6 @@ sub install_default { },1,0,0); } -sub my_cmp { - my($one,$two) = @_; - local(*F,*T); - my $diff = 0; - open T, $two or return 1; - open F, $one or Carp::croak("Couldn't open $one: $!"); - my($fr, $tr, $fbuf, $tbuf, $size); - $size = 1024; - # print "Reading $one\n"; - while ( $fr = read(F,$fbuf,$size)) { - unless ( - $tr = read(T,$tbuf,$size) and - $tbuf eq $fbuf - ){ - # print "diff "; - $diff++; - last; - } - # print "$fr/$tr "; - } - # print "\n"; - close F; - close T; - $diff; -} - sub uninstall { my($fil,$verbose,$nonono) = @_; die "no packlist file found: $fil" unless -f $fil; @@ -226,7 +201,7 @@ sub inc_uninstall { my $diff = 0; if ( -f $targetfile && -s _ == -s $file) { # We have a good chance, we can skip this one - $diff = my_cmp($file,$targetfile); + $diff = compare($file,$targetfile); } else { print "#$file and $targetfile differ\n" if $verbose>1; $diff++; @@ -253,6 +228,7 @@ sub pm_to_blib { use File::Basename qw(dirname); use File::Copy qw(copy); use File::Path qw(mkpath); + use File::Compare qw(compare); use AutoSplit; # my $my_req = $self->catfile(qw(auto ExtUtils Install forceunlink.al)); # require $my_req; # Hairy, but for the first @@ -272,7 +248,7 @@ sub pm_to_blib { mkpath($autodir,0,0755); foreach (keys %$fromto) { next if -f $fromto->{$_} && -M $fromto->{$_} < -M $_; - unless (my_cmp($_,$fromto->{$_})){ + unless (compare($_,$fromto->{$_})){ print "Skip $fromto->{$_} (unchanged)\n"; next; } diff --git a/lib/ExtUtils/Liblist.pm b/lib/ExtUtils/Liblist.pm index fed25ae..d821e83 100644 --- a/lib/ExtUtils/Liblist.pm +++ b/lib/ExtUtils/Liblist.pm @@ -24,7 +24,7 @@ sub _unix_os2_ext { $potential_libs .= $Config{libs}; } return ("", "", "", "") unless $potential_libs; - print STDOUT "Potential libraries are '$potential_libs':\n" if $verbose; + warn "Potential libraries are '$potential_libs':\n" if $verbose; my($so) = $Config{'so'}; my($libs) = $Config{'libs'}; @@ -34,7 +34,6 @@ sub _unix_os2_ext { # compute $extralibs, $bsloadlibs and $ldloadlibs from # $potential_libs # this is a rewrite of Andy Dougherty's extliblist in perl - # its home is in /ext/util my(@searchpath); # from "-L/path" entries in $potential_libs my(@libpath) = split " ", $Config{'libpth'}; @@ -49,12 +48,12 @@ sub _unix_os2_ext { if ($thislib =~ s/^(-[LR])//){ # save path flag type my($ptype) = $1; unless (-d $thislib){ - print STDOUT "$ptype$thislib ignored, directory does not exist\n" + warn "$ptype$thislib ignored, directory does not exist\n" if $verbose; next; } unless ($self->file_name_is_absolute($thislib)) { - print STDOUT "Warning: $ptype$thislib changed to $ptype$pwd/$thislib\n"; + warn "Warning: $ptype$thislib changed to $ptype$pwd/$thislib\n"; $thislib = $self->catdir($pwd,$thislib); } push(@searchpath, $thislib); @@ -65,7 +64,7 @@ sub _unix_os2_ext { # Handle possible library arguments. unless ($thislib =~ s/^-l//){ - print STDOUT "Unrecognized argument in LIBS ignored: '$thislib'\n"; + warn "Unrecognized argument in LIBS ignored: '$thislib'\n"; next; } @@ -125,10 +124,10 @@ sub _unix_os2_ext { # # , the compilation tools expand the environment variables.) } else { - print STDOUT "$thislib not found in $thispth\n" if $verbose; + warn "$thislib not found in $thispth\n" if $verbose; next; } - print STDOUT "'-l$thislib' found at $fullname\n" if $verbose; + warn "'-l$thislib' found at $fullname\n" if $verbose; my($fullnamedir) = dirname($fullname); push @ld_run_path, $fullnamedir unless $ld_run_path_seen{$fullnamedir}++; $found++; @@ -174,7 +173,7 @@ sub _unix_os2_ext { } last; # found one here so don't bother looking further } - print STDOUT "Note (probably harmless): " + warn "Note (probably harmless): " ."No library found for -l$thislib\n" unless $found_lib>0; } @@ -202,7 +201,7 @@ sub _win32_ext { $potential_libs .= " " if $potential_libs; $potential_libs .= $libs; } - print STDOUT "Potential libraries are '$potential_libs':\n" if $verbose; + warn "Potential libraries are '$potential_libs':\n" if $verbose; # compute $extralibs from $potential_libs @@ -218,13 +217,13 @@ sub _win32_ext { # Handle possible linker path arguments. if ($thislib =~ s/^-L// and not -d $thislib) { - print STDOUT "-L$thislib ignored, directory does not exist\n" + warn "-L$thislib ignored, directory does not exist\n" if $verbose; next; } elsif (-d $thislib) { unless ($self->file_name_is_absolute($thislib)) { - print STDOUT "Warning: -L$thislib changed to -L$pwd/$thislib\n"; + warn "Warning: -L$thislib changed to -L$pwd/$thislib\n"; $thislib = $self->catdir($pwd,$thislib); } push(@searchpath, $thislib); @@ -238,22 +237,22 @@ sub _win32_ext { my($found_lib)=0; foreach $thispth (@searchpath, @libpath){ unless (-f ($fullname="$thispth\\$thislib")) { - print STDOUT "$thislib not found in $thispth\n" if $verbose; + warn "$thislib not found in $thispth\n" if $verbose; next; } - print STDOUT "'$thislib' found at $fullname\n" if $verbose; + warn "'$thislib' found at $fullname\n" if $verbose; $found++; $found_lib++; push(@extralibs, $fullname); last; } - print STDOUT "Note (probably harmless): " + warn "Note (probably harmless): " ."No library found for '$thislib'\n" unless $found_lib>0; } return ('','','','') unless $found; $lib = join(' ',@extralibs); - print "Result: $lib\n" if $verbose; + warn "Result: $lib\n" if $verbose; wantarray ? ($lib, '', $lib, '') : $lib; } @@ -275,7 +274,7 @@ sub _vms_ext { 'Xmu' => 'DECW$XMULIBSHR'); if ($Config{'vms_cc_type'} ne 'decc') { $libmap{'curses'} = 'VAXCCURSE'; } - print STDOUT "Potential libraries are '$potential_libs'\n" if $verbose; + warn "Potential libraries are '$potential_libs'\n" if $verbose; # First, sort out directories and library names in the input foreach $lib (split ' ',$potential_libs) { @@ -292,11 +291,11 @@ sub _vms_ext { # path in a logical name.) foreach $dir (@dirs) { unless (-d $dir) { - print STDOUT "Skipping nonexistent Directory $dir\n" if $verbose > 1; + warn "Skipping nonexistent Directory $dir\n" if $verbose > 1; $dir = ''; next; } - print STDOUT "Resolving directory $dir\n" if $verbose; + warn "Resolving directory $dir\n" if $verbose; if ($self->file_name_is_absolute($dir)) { $dir = $self->fixpath($dir,1); } else { $dir = $self->catdir($cwd,$dir); } } @@ -321,24 +320,24 @@ sub _vms_ext { push(@variants,"lib$lib") if $lib !~ /[:>\]]/; } push(@variants,$lib); - print STDOUT "Looking for $lib\n" if $verbose; + warn "Looking for $lib\n" if $verbose; foreach $variant (@variants) { foreach $dir (@dirs) { my($type); $name = "$dir$variant"; - print "\tChecking $name\n" if $verbose > 2; + warn "\tChecking $name\n" if $verbose > 2; if (-f ($test = VMS::Filespec::rmsexpand($name))) { # It's got its own suffix, so we'll have to figure out the type if ($test =~ /(?:$so|exe)$/i) { $type = 'sh'; } elsif ($test =~ /(?:$lib_ext|olb)$/i) { $type = 'olb'; } elsif ($test =~ /(?:$obj_ext|obj)$/i) { - print STDOUT "Note (probably harmless): " + warn "Note (probably harmless): " ."Plain object file $test found in library list\n"; $type = 'obj'; } else { - print STDOUT "Note (probably harmless): " + warn "Note (probably harmless): " ."Unknown library type for $test; assuming shared\n"; $type = 'sh'; } @@ -357,7 +356,7 @@ sub _vms_ext { elsif (not length($ctype) and # If we've got a lib already, don't bother ( -f ($test = VMS::Filespec::rmsexpand($name,$obj_ext)) or -f ($test = VMS::Filespec::rmsexpand($name,'.obj')))) { - print STDOUT "Note (probably harmless): " + warn "Note (probably harmless): " ."Plain object file $test found in library list\n"; $type = 'obj'; $name = $test unless $test =~ /obj;?\d*$/i; @@ -370,11 +369,11 @@ sub _vms_ext { if ($ctype) { eval '$' . $ctype . "{'$cand'}++"; die "Error recording library: $@" if $@; - print STDOUT "\tFound as $cand (really $test), type $ctype\n" if $verbose > 1; + warn "\tFound as $cand (really $test), type $ctype\n" if $verbose > 1; next LIB; } } - print STDOUT "Note (probably harmless): " + warn "Note (probably harmless): " ."No library found for $lib\n"; } @@ -387,7 +386,7 @@ sub _vms_ext { push(@libs, map { "$_/Library" } sort keys %olb); push(@libs, map { "$_/Share" } sort keys %sh); $lib = join(' ',@libs); - print "Result: $lib\n" if $verbose; + warn "Result: $lib\n" if $verbose; wantarray ? ($lib, '', $lib, '') : $lib; } diff --git a/lib/ExtUtils/MM_Unix.pm b/lib/ExtUtils/MM_Unix.pm index 85b0c1b..4f7a9e8 100644 --- a/lib/ExtUtils/MM_Unix.pm +++ b/lib/ExtUtils/MM_Unix.pm @@ -1127,7 +1127,12 @@ sub fixin { # stolen from the pink Camel book, more or less # Now look (in reverse) for interpreter in absolute PATH (unless perl). if ($cmd eq "perl") { - $interpreter = $Config{perlpath}; + if ($Config{startperl} =~ m,^\#!.*/perl,) { + $interpreter = $Config{startperl}; + $interpreter =~ s,^\#!,,; + } else { + $interpreter = $Config{perlpath}; + } } else { my(@absdirs) = reverse grep {$self->file_name_is_absolute} $self->path; $interpreter = ''; @@ -2935,11 +2940,13 @@ sub test { if (!$tests && -d 't') { $tests = $Is_Win32 ? join(' ', ) : 't/*.t'; } + # note: 'test.pl' name is also hardcoded in init_dirscan() my(@m); push(@m," TEST_VERBOSE=0 TEST_TYPE=test_\$(LINKTYPE) TEST_FILE = test.pl +TEST_FILES = $tests TESTDB_SW = -d testdb :: testdb_\$(LINKTYPE) @@ -2953,8 +2960,8 @@ test :: \$(TEST_TYPE) push(@m, "\n"); push(@m, "test_dynamic :: pure_all\n"); - push(@m, $self->test_via_harness('$(FULLPERL)', $tests)) if $tests; - push(@m, $self->test_via_script('$(FULLPERL)', 'test.pl')) if -f "test.pl"; + push(@m, $self->test_via_harness('$(FULLPERL)', '$(TEST_FILES)')) if $tests; + push(@m, $self->test_via_script('$(FULLPERL)', '$(TEST_FILE)')) if -f "test.pl"; push(@m, "\n"); push(@m, "testdb_dynamic :: pure_all\n"); @@ -2966,8 +2973,8 @@ test :: \$(TEST_TYPE) if ($self->needs_linking()) { push(@m, "test_static :: pure_all \$(MAP_TARGET)\n"); - push(@m, $self->test_via_harness('./$(MAP_TARGET)', $tests)) if $tests; - push(@m, $self->test_via_script('./$(MAP_TARGET)', 'test.pl')) if -f "test.pl"; + push(@m, $self->test_via_harness('./$(MAP_TARGET)', '$(TEST_FILES)')) if $tests; + push(@m, $self->test_via_script('./$(MAP_TARGET)', '$(TEST_FILE)')) if -f "test.pl"; push(@m, "\n"); push(@m, "testdb_static :: pure_all \$(MAP_TARGET)\n"); push(@m, $self->test_via_script('./$(MAP_TARGET) $(TESTDB_SW)', '$(TEST_FILE)')); diff --git a/lib/ExtUtils/xsubpp b/lib/ExtUtils/xsubpp index ac1378d..04de166 100755 --- a/lib/ExtUtils/xsubpp +++ b/lib/ExtUtils/xsubpp @@ -87,7 +87,7 @@ sub Q ; # Global Constants -$XSUBPP_version = "1.9504"; +$XSUBPP_version = "1.9505"; my ($Is_VMS, $SymSet); if ($^O eq 'VMS') { @@ -294,7 +294,7 @@ sub print_section { do { $_ = shift(@line) } while !/\S/ && @line; print("#line ", $line_no[@line_no - @line -1], " \"$filename\"\n") - if $WantLineNumbers && !/^\s*#\s*line\b/; + if $WantLineNumbers && !/^\s*#\s*line\b/ && !/^#if XSubPPtmp/; for (; defined($_) && !/^$BLOCK_re/o; $_ = shift(@line)) { print "$_\n"; } diff --git a/lib/File/DosGlob.pm b/lib/File/DosGlob.pm index e0887d1..4597c71 100644 --- a/lib/File/DosGlob.pm +++ b/lib/File/DosGlob.pm @@ -100,16 +100,55 @@ sub doglob { } # -# this can be used to override CORE::glob -# by saying C. +# this can be used to override CORE::glob in a specific +# package by saying C in that +# namespace. # -sub glob { doglob(1,@_) } + +# context (keyed by second cxix arg provided by core) +my %iter; +my %entries; + +sub glob { + my $pat = shift; + my $cxix = shift; + + # glob without args defaults to $_ + $pat = $_ unless defined $pat; + + # assume global context if not provided one + $cxix = '_G_' unless defined $cxix; + $iter{$cxix} = 0 unless exists $iter{$cxix}; + + # if we're just beginning, do it all first + if ($iter{$cxix} == 0) { + $entries{$cxix} = [doglob(1,$pat)]; + } + + # chuck it all out, quick or slow + if (wantarray) { + delete $iter{$cxix}; + return @{delete $entries{$cxix}}; + } + else { + if ($iter{$cxix} = scalar @{$entries{$cxix}}) { + return shift @{$entries{$cxix}}; + } + else { + # return undef for EOL + delete $iter{$cxix}; + delete $entries{$cxix}; + return undef; + } + } +} sub import { my $pkg = shift; my $callpkg = caller(0); my $sym = shift; - *{$callpkg.'::'.$sym} = \&{$pkg.'::'.$sym} if $sym eq 'glob'; + *{$callpkg.'::'.$sym} = \&{$pkg.'::'.$sym} + if defined($sym) and $sym eq 'glob'; } 1; @@ -125,11 +164,14 @@ perlglob.bat - a more capable perlglob.exe replacement =head1 SYNOPSIS require 5.004; - use File::DosGlob 'glob'; # override CORE::glob + + # override CORE::glob in current package + use File::DosGlob 'glob'; + @perlfiles = glob "..\\pe?l/*.p?"; print <..\\pe?l/*.p?>; - # from the command line + # from the command line (overrides only in main::) > perl -MFile::DosGlob=glob -e "print <../pe*/*p?>" > perlglob ../pe*/*p? @@ -155,7 +197,10 @@ to standard output. While one may replace perlglob.exe with this, usage by overriding CORE::glob via importation should be much more efficient, because it avoids launching a separate process, and is therefore strongly -recommended. +recommended. Note that it is currently possible to override +builtins like glob() only on a per-package basis, not "globally". +Thus, every namespace that wants to override glob() must explicitly +request the override. See L. Extending it to csh patterns is left as an exercise to the reader. @@ -178,6 +223,10 @@ Gurusamy Sarathy =item * +Scalar context, independent iterator context fixes (GSAR 15-SEP-97) + +=item * + A few dir-vs-file optimizations result in glob importation being 10 times faster than using perlglob.exe, and using perlglob.bat is only twice as slow as perlglob.exe (GSAR 28-MAY-97) diff --git a/lib/File/Find.pm b/lib/File/Find.pm index 1d565f2..033cfe5 100644 --- a/lib/File/Find.pm +++ b/lib/File/Find.pm @@ -65,6 +65,10 @@ that don't resolve: -l && !-e && print "bogus link: $File::Find::name\n"; } +=head1 BUGS + +There is no way to make find or finddepth follow symlinks. + =cut @ISA = qw(Exporter); diff --git a/lib/FileHandle.pm b/lib/FileHandle.pm index 0264b61..455fc63 100644 --- a/lib/FileHandle.pm +++ b/lib/FileHandle.pm @@ -69,7 +69,8 @@ import IO::Handle grep { !defined(&$_) } @EXPORT, @EXPORT_OK; sub import { my $pkg = shift; my $callpkg = caller; - Exporter::export $pkg, $callpkg, @_; + require Exporter; + Exporter::export($pkg, $callpkg, @_); # # If the Fcntl extension is available, @@ -77,7 +78,7 @@ sub import { # eval { require Fcntl; - Exporter::export 'Fcntl', $callpkg; + Exporter::export('Fcntl', $callpkg); }; } diff --git a/lib/Getopt/Long.pm b/lib/Getopt/Long.pm index b0bcf6b..2b05300 100644 --- a/lib/Getopt/Long.pm +++ b/lib/Getopt/Long.pm @@ -2,12 +2,12 @@ package Getopt::Long; -# RCS Status : $Id: GetoptLong.pm,v 2.10 1997-04-18 22:21:10+02 jv Exp $ +# RCS Status : $Id: GetoptLong.pm,v 2.11 1997-09-17 12:23:51+02 jv Exp $ # Author : Johan Vromans # Created On : Tue Sep 11 15:00:12 1990 # Last Modified By: Johan Vromans -# Last Modified On: Wed Apr 16 16:27:33 1997 -# Update Count : 597 +# Last Modified On: Wed Sep 17 12:20:10 1997 +# Update Count : 608 # Status : Released =head1 NAME @@ -56,8 +56,9 @@ value. With a command line of "--size 24" this will cause the variable $offset to get the value 24. Alternatively, the first argument to GetOptions may be a reference to -a HASH describing the linkage for the options. The following call is -equivalent to the example above: +a HASH describing the linkage for the options, or an object whose +class is based on a HASH. The following call is equivalent to the +example above: %optctl = ("size" => \$offset); GetOptions(\%optctl, "size=i"); @@ -525,7 +526,7 @@ BEGIN { require 5.003; use Exporter (); use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); - $VERSION = sprintf("%d.%02d", q$Revision: 2.10 $ =~ /(\d+)\.(\d+)/); + $VERSION = sprintf("%d.%02d", q$Revision: 2.11 $ =~ /(\d+)\.(\d+)/); @ISA = qw(Exporter); @EXPORT = qw(&GetOptions $REQUIRE_ORDER $PERMUTE $RETURN_IN_ORDER); @@ -576,7 +577,7 @@ sub GetOptions { $genprefix = $gen_prefix; # so we can call the same module many times $error = 0; - print STDERR ('GetOptions $Revision: 2.10 $ ', + print STDERR ('GetOptions $Revision: 2.11 $ ', "[GetOpt::Long $Getopt::Long::VERSION] -- ", "called from package \"$pkg\".\n", " (@ARGV)\n", @@ -591,9 +592,13 @@ sub GetOptions { if $debug; # Check for ref HASH as first argument. + # First argument may be an object. It's OK to use this as long + # as it is really a hash underneath. $userlinkage = undef; - if ( ref($optionlist[0]) && ref($optionlist[0]) eq 'HASH' ) { + if ( ref($optionlist[0]) and + "$optionlist[0]" =~ /^(?:.*\=)?HASH\([^\(]*\)$/ ) { $userlinkage = shift (@optionlist); + print STDERR ("=> user linkage: $userlinkage\n") if $debug; } # See if the first element of the optionlist contains option @@ -1145,7 +1150,11 @@ $find_option = sub { elsif ( $type eq "n" || $type eq "i" ) { # numeric/integer if ( $arg !~ /^-?[0-9]+$/ ) { if ( defined $optarg || $mand eq "=" ) { - return 0 if $passthrough; + if ( $passthrough ) { + unshift (@ARGV, defined $rest ? $starter.$rest : $arg) + unless defined $optarg; + return 0; + } print STDERR ("Value \"", $arg, "\" invalid for option ", $opt, " (number expected)\n"); $error++; @@ -1165,7 +1174,11 @@ $find_option = sub { elsif ( $type eq "f" ) { # real number, int is also ok if ( $arg !~ /^-?[0-9.]+([eE]-?[0-9]+)?$/ ) { if ( defined $optarg || $mand eq "=" ) { - return 0 if $passthrough; + if ( $passthrough ) { + unshift (@ARGV, defined $rest ? $starter.$rest : $arg) + unless defined $optarg; + return 0; + } print STDERR ("Value \"", $arg, "\" invalid for option ", $opt, " (real number expected)\n"); $error++; diff --git a/lib/Getopt/Std.pm b/lib/Getopt/Std.pm index fee0d33..2788293 100644 --- a/lib/Getopt/Std.pm +++ b/lib/Getopt/Std.pm @@ -67,7 +67,7 @@ sub getopt ($;$) { $$hash{$first} = $rest; } else { - eval "\$opt_$first = \$rest;"; + ${"opt_$first"} = $rest; push( @EXPORT, "\$opt_$first" ); } } @@ -76,7 +76,7 @@ sub getopt ($;$) { $$hash{$first} = 1; } else { - eval "\$opt_$first = 1;"; + ${"opt_$first"} = 1; push( @EXPORT, "\$opt_$first" ); } if ($rest ne '') { @@ -116,7 +116,7 @@ sub getopts ($;$) { $$hash{$first} = $rest; } else { - eval "\$opt_$first = \$rest;"; + ${"opt_$first"} = $rest; push( @EXPORT, "\$opt_$first" ); } } @@ -125,7 +125,7 @@ sub getopts ($;$) { $$hash{$first} = 1; } else { - eval "\$opt_$first = 1"; + ${"opt_$first"} = 1; push( @EXPORT, "\$opt_$first" ); } if($rest eq '') { diff --git a/lib/Math/Complex.pm b/lib/Math/Complex.pm index 33c6023..64477fa 100644 --- a/lib/Math/Complex.pm +++ b/lib/Math/Complex.pm @@ -1,26 +1,29 @@ -# $RCSFile$ # # Complex numbers and associated mathematical functions -# -- Raphael Manfredi, September 1996 -# -- Jarkko Hietaniemi, March-April 1997 +# -- Raphael Manfredi September 1996 +# -- Jarkko Hietaniemi March-October 1997 +# -- Daniel S. Lewart September-October 1997 +# require Exporter; package Math::Complex; +$VERSION = 1.05; + +# $Id: Complex.pm,v 1.2 1997/10/15 10:08:39 jhi Exp $ + use strict; use vars qw($VERSION @ISA @EXPORT %EXPORT_TAGS $package $display - $i $logn %logn); + $i $ip2 $logn %logn); @ISA = qw(Exporter); -$VERSION = 1.01; - my @trig = qw( pi - sin cos tan + tan csc cosec sec cot cotan asin acos atan acsc acosec asec acot acotan @@ -32,7 +35,7 @@ my @trig = qw( @EXPORT = (qw( i Re Im arg - sqrt exp log ln + sqrt log ln log10 logn cbrt root cplx cplxe ), @@ -99,8 +102,11 @@ sub make { sub emake { my $self = bless {}, shift; my ($rho, $theta) = @_; - $theta += pi() if $rho < 0; - $self->{'polar'} = [abs($rho), $theta]; + if ($rho < 0) { + $rho = -$rho; + $theta = ($theta <= 0) ? $theta + pi() : $theta - pi(); + } + $self->{'polar'} = [$rho, $theta]; $self->{p_dirty} = 0; $self->{c_dirty} = 1; return $self; @@ -133,18 +139,30 @@ sub cplxe { # # pi # -# The number defined as 2 * pi = 360 degrees +# The number defined as pi = 180 degrees # - use constant pi => 4 * atan2(1, 1); # -# log2inv +# pit2 # -# Used in log10(). +# The full circle +# +use constant pit2 => 2 * pi; + # +# pip2 +# +# The quarter circle +# +use constant pip2 => pi / 2; -use constant log10inv => 1 / log(10); +# +# uplog10 +# +# Used in log10(). +# +use constant uplog10 => 1 / log(10); # # i @@ -155,7 +173,7 @@ sub i () { return $i if ($i); $i = bless {}; $i->{'cartesian'} = [0, 1]; - $i->{'polar'} = [1, pi/2]; + $i->{'polar'} = [1, pip2]; $i->{c_dirty} = 0; $i->{p_dirty} = 0; return $i; @@ -242,15 +260,28 @@ sub minus { # Computes z1*z2. # sub multiply { - my ($z1, $z2, $regular) = @_; - my ($r1, $t1) = @{$z1->polar}; - $z2 = cplxe(abs($z2), $z2 >= 0 ? 0 : pi) unless ref $z2; - my ($r2, $t2) = @{$z2->polar}; - unless (defined $regular) { - $z1->set_polar([$r1 * $r2, $t1 + $t2]); + my ($z1, $z2, $regular) = @_; + if ($z1->{p_dirty} == 0 and ref $z2 and $z2->{p_dirty} == 0) { + # if both polar better use polar to avoid rounding errors + my ($r1, $t1) = @{$z1->polar}; + my ($r2, $t2) = @{$z2->polar}; + my $t = $t1 + $t2; + if ($t > pi()) { $t -= pit2 } + elsif ($t <= -pi()) { $t += pit2 } + unless (defined $regular) { + $z1->set_polar([$r1 * $r2, $t]); return $z1; + } + return (ref $z1)->emake($r1 * $r2, $t); + } else { + my ($x1, $y1) = @{$z1->cartesian}; + if (ref $z2) { + my ($x2, $y2) = @{$z2->cartesian}; + return (ref $z1)->make($x1*$x2-$y1*$y2, $x1*$y2+$y1*$x2); + } else { + return (ref $z1)->make($x1*$z2, $y1*$z2); + } } - return (ref $z1)->emake($r1 * $r2, $t1 + $t2); } # @@ -268,7 +299,7 @@ sub _divbyzero { } my @up = caller(1); - + $mess .= "Died at $up[1] line $up[2].\n"; die $mess; @@ -281,20 +312,45 @@ sub _divbyzero { # sub divide { my ($z1, $z2, $inverted) = @_; - my ($r1, $t1) = @{$z1->polar}; - $z2 = cplxe(abs($z2), $z2 >= 0 ? 0 : pi) unless ref $z2; - my ($r2, $t2) = @{$z2->polar}; - unless (defined $inverted) { - _divbyzero "$z1/0" if ($r2 == 0); - $z1->set_polar([$r1 / $r2, $t1 - $t2]); - return $z1; - } - if ($inverted) { + if ($z1->{p_dirty} == 0 and ref $z2 and $z2->{p_dirty} == 0) { + # if both polar better use polar to avoid rounding errors + my ($r1, $t1) = @{$z1->polar}; + my ($r2, $t2) = @{$z2->polar}; + my $t; + if ($inverted) { _divbyzero "$z2/0" if ($r1 == 0); - return (ref $z1)->emake($r2 / $r1, $t2 - $t1); - } else { + $t = $t2 - $t1; + if ($t > pi()) { $t -= pit2 } + elsif ($t <= -pi()) { $t += pit2 } + return (ref $z1)->emake($r2 / $r1, $t); + } else { _divbyzero "$z1/0" if ($r2 == 0); - return (ref $z1)->emake($r1 / $r2, $t1 - $t2); + $t = $t1 - $t2; + if ($t > pi()) { $t -= pit2 } + elsif ($t <= -pi()) { $t += pit2 } + return (ref $z1)->emake($r1 / $r2, $t); + } + } else { + my ($d, $x2, $y2); + if ($inverted) { + ($x2, $y2) = @{$z1->cartesian}; + $d = $x2*$x2 + $y2*$y2; + _divbyzero "$z2/0" if $d == 0; + return (ref $z1)->make(($x2*$z2)/$d, -($y2*$z2)/$d); + } else { + my ($x1, $y1) = @{$z1->cartesian}; + if (ref $z2) { + ($x2, $y2) = @{$z2->cartesian}; + $d = $x2*$x2 + $y2*$y2; + _divbyzero "$z1/0" if $d == 0; + my $u = ($x1*$x2 + $y1*$y2)/$d; + my $v = ($y1*$x2 - $x1*$y2)/$d; + return (ref $z1)->make($u, $v); + } else { + _divbyzero "$z1/0" if $z2 == 0; + return (ref $z1)->make($x1/$z2, $y1/$z2); + } + } } } @@ -307,7 +363,7 @@ sub _zerotozero { my $mess = "The zero raised to the zeroth power is not defined.\n"; my @up = caller(1); - + $mess .= "Died at $up[1] line $up[2].\n"; die $mess; @@ -330,14 +386,7 @@ sub power { return 0 if ($z1z); return 1 if ($z2z or $z1 == 1); } - $z2 = cplx($z2) unless ref $z2; - unless (defined $inverted) { - my $z3 = exp($z2 * log $z1); - $z1->set_cartesian([@{$z3->cartesian}]); - return $z1; - } - return exp($z2 * log $z1) unless $inverted; - return exp($z1 * log $z2); + return $inverted ? exp($z1 * log $z2) : exp($z2 * log $z1); } # @@ -364,7 +413,8 @@ sub negate { my ($z) = @_; if ($z->{c_dirty}) { my ($r, $t) = @{$z->polar}; - return (ref $z)->emake($r, pi + $t); + $t = ($t <= 0) ? $t + pi : $t - pi; + return (ref $z)->emake($r, $t); } my ($re, $im) = @{$z->cartesian}; return (ref $z)->make(-$re, -$im); @@ -392,9 +442,8 @@ sub conjugate { # sub abs { my ($z) = @_; - return abs($z) unless ref $z; my ($r, $t) = @{$z->polar}; - return abs($r); + return $r; } # @@ -406,6 +455,8 @@ sub arg { my ($z) = @_; return ($z < 0 ? pi : 0) unless ref $z; my ($r, $t) = @{$z->polar}; + if ($t > pi()) { $t -= pit2 } + elsif ($t <= -pi()) { $t += pit2 } return $t; } @@ -416,7 +467,9 @@ sub arg { # sub sqrt { my ($z) = @_; - $z = cplx($z, 0) unless ref $z; + return $z >= 0 ? sqrt($z) : cplx(0, sqrt(-$z)) unless ref $z; + my ($re, $im) = @{$z->cartesian}; + return cplx($re < 0 ? (0, sqrt(-$re)) : (sqrt($re), 0)) if $im == 0; my ($r, $t) = @{$z->polar}; return (ref $z)->emake(sqrt($r), $t/2); } @@ -428,9 +481,10 @@ sub sqrt { # sub cbrt { my ($z) = @_; - return cplx($z, 0) ** (1/3) unless ref $z; + return $z < 0 ? -exp(log(-$z)/3) : ($z > 0 ? exp(log($z)/3): 0) + unless ref $z; my ($r, $t) = @{$z->polar}; - return (ref $z)->emake($r**(1/3), $t/3); + return (ref $z)->emake(exp(log($r)/3), $t/3); } # @@ -442,7 +496,7 @@ sub _rootbad { my $mess = "Root $_[0] not defined, root must be positive integer.\n"; my @up = caller(1); - + $mess .= "Died at $up[1] line $up[2].\n"; die $mess; @@ -464,7 +518,7 @@ sub root { my ($r, $t) = ref $z ? @{$z->polar} : (abs($z), $z >= 0 ? 0 : pi); my @root; my $k; - my $theta_inc = 2 * pi / $n; + my $theta_inc = pit2 / $n; my $rho = $r ** (1/$n); my $theta; my $complex = ref($z) || $package; @@ -505,7 +559,6 @@ sub Im { # sub exp { my ($z) = @_; - $z = cplx($z, 0) unless ref $z; my ($x, $y) = @{$z->cartesian}; return (ref $z)->emake(exp($x), $y); } @@ -513,7 +566,7 @@ sub exp { # # _logofzero # -# Die on division by zero. +# Die on logarithm of zero. # sub _logofzero { my $mess = "$_[0]: Logarithm of zero.\n"; @@ -525,7 +578,7 @@ sub _logofzero { } my @up = caller(1); - + $mess .= "Died at $up[1] line $up[2].\n"; die $mess; @@ -538,11 +591,14 @@ sub _logofzero { # sub log { my ($z) = @_; - $z = cplx($z, 0) unless ref $z; - my ($x, $y) = @{$z->cartesian}; + unless (ref $z) { + _logofzero("log") if $z == 0; + return $z > 0 ? log($z) : cplx(log(-$z), pi); + } my ($r, $t) = @{$z->polar}; - $t -= 2 * pi if ($t > pi() and $x < 0); - $t += 2 * pi if ($t < -pi() and $x < 0); + _logofzero("log") if $r == 0; + if ($t > pi()) { $t -= pit2 } + elsif ($t <= -pi()) { $t += pit2 } return (ref $z)->make(log($r), $t); } @@ -560,11 +616,7 @@ sub ln { Math::Complex::log(@_) } # sub log10 { - my ($z) = @_; - - return log(cplx($z, 0)) * log10inv unless ref $z; - my ($r, $t) = @{$z->polar}; - return (ref $z)->make(log($r) * log10inv, $t * log10inv); + return Math::Complex::log($_[0]) * uplog10; } # @@ -587,7 +639,6 @@ sub logn { # sub cos { my ($z) = @_; - $z = cplx($z, 0) unless ref $z; my ($x, $y) = @{$z->cartesian}; my $ey = exp($y); my $ey_1 = 1 / $ey; @@ -602,7 +653,6 @@ sub cos { # sub sin { my ($z) = @_; - $z = cplx($z, 0) unless ref $z; my ($x, $y) = @{$z->cartesian}; my $ey = exp($y); my $ey_1 = 1 / $ey; @@ -656,7 +706,7 @@ sub cosec { Math::Complex::csc(@_) } # # cot # -# Computes cot(z) = 1 / tan(z). +# Computes cot(z) = cos(z) / sin(z). # sub cot { my ($z) = @_; @@ -678,21 +728,20 @@ sub cotan { Math::Complex::cot(@_) } # Computes the arc cosine acos(z) = -i log(z + sqrt(z*z-1)). # sub acos { - my ($z) = @_; - $z = cplx($z, 0) unless ref $z; - my ($re, $im) = @{$z->cartesian}; - return atan2(sqrt(1 - $re * $re), $re) - if ($im == 0 and abs($re) <= 1.0); - my $acos = ~i * log($z + sqrt($z*$z - 1)); - if ($im == 0 || - (abs($re) < 1 && abs($im) < 1) || - (abs($re) > 1 && abs($im) > 1 - && !($re > 1 && $im > 1) - && !($re < -1 && $im < -1))) { - # this rule really, REALLY, must be simpler - return -$acos; - } - return $acos; + my $z = $_[0]; + return atan2(sqrt(1-$z*$z), $z) if (! ref $z) && abs($z) <= 1; + my ($x, $y) = ref $z ? @{$z->cartesian} : ($z, 0); + my $t1 = sqrt(($x+1)*($x+1) + $y*$y); + my $t2 = sqrt(($x-1)*($x-1) + $y*$y); + my $alpha = ($t1 + $t2)/2; + my $beta = ($t1 - $t2)/2; + $alpha = 1 if $alpha < 1; + if ($beta > 1) { $beta = 1 } + elsif ($beta < -1) { $beta = -1 } + my $u = atan2(sqrt(1-$beta*$beta), $beta); + my $v = log($alpha + sqrt($alpha*$alpha-1)); + $v = -$v if $y > 0 || ($y == 0 && $x < -1); + return $package->make($u, $v); } # @@ -701,12 +750,20 @@ sub acos { # Computes the arc sine asin(z) = -i log(iz + sqrt(1-z*z)). # sub asin { - my ($z) = @_; - $z = cplx($z, 0) unless ref $z; - my ($re, $im) = @{$z->cartesian}; - return atan2($re, sqrt(1 - $re * $re)) - if ($im == 0 and abs($re) <= 1.0); - return ~i * log(i * $z + sqrt(1 - $z*$z)); + my $z = $_[0]; + return atan2($z, sqrt(1-$z*$z)) if (! ref $z) && abs($z) <= 1; + my ($x, $y) = ref $z ? @{$z->cartesian} : ($z, 0); + my $t1 = sqrt(($x+1)*($x+1) + $y*$y); + my $t2 = sqrt(($x-1)*($x-1) + $y*$y); + my $alpha = ($t1 + $t2)/2; + my $beta = ($t1 - $t2)/2; + $alpha = 1 if $alpha < 1; + if ($beta > 1) { $beta = 1 } + elsif ($beta < -1) { $beta = -1 } + my $u = atan2($beta, sqrt(1-$beta*$beta)); + my $v = -log($alpha + sqrt($alpha*$alpha-1)); + $v = -$v if $y > 0 || ($y == 0 && $x < -1); + return $package->make($u, $v); } # @@ -716,10 +773,12 @@ sub asin { # sub atan { my ($z) = @_; - $z = cplx($z, 0) unless ref $z; + return atan2($z, 1) unless ref $z; _divbyzero "atan(i)" if ( $z == i); _divbyzero "atan(-i)" if (-$z == i); - return i/2*log((i + $z) / (i - $z)); + my $log = log((i + $z) / (i - $z)); + $ip2 = 0.5 * i unless defined $ip2; + return $ip2 * $log; } # @@ -730,16 +789,7 @@ sub atan { sub asec { my ($z) = @_; _divbyzero "asec($z)", $z if ($z == 0); - $z = cplx($z, 0) unless ref $z; - my ($re, $im) = @{$z->cartesian}; - if ($im == 0 && abs($re) >= 1.0) { - my $ire = 1 / $re; - return atan2(sqrt(1 - $ire * $ire), $ire); - } - my $asec = acos(1 / $z); - return ~$asec if $re < 0 && $re > -1 && $im == 0; - return -$asec if $im && !($re > 0 && $im > 0) && !($re < 0 && $im < 0); - return $asec; + return acos(1 / $z); } # @@ -750,15 +800,7 @@ sub asec { sub acsc { my ($z) = @_; _divbyzero "acsc($z)", $z if ($z == 0); - $z = cplx($z, 0) unless ref $z; - my ($re, $im) = @{$z->cartesian}; - if ($im == 0 && abs($re) >= 1.0) { - my $ire = 1 / $re; - return atan2($ire, sqrt(1 - $ire * $ire)); - } - my $acsc = asin(1 / $z); - return ~$acsc if $re < 0 && $re > -1 && $im == 0; - return $acsc; + return asin(1 / $z); } # @@ -775,8 +817,7 @@ sub acosec { Math::Complex::acsc(@_) } # sub acot { my ($z) = @_; - _divbyzero "acot($z)" if ($z == 0); - $z = cplx($z, 0) unless ref $z; + return ($z >= 0) ? atan2(1, $z) : atan2(-1, -$z) unless ref $z; _divbyzero "acot(i)", if ( $z == i); _divbyzero "acot(-i)" if (-$z == i); return atan(1 / $z); @@ -796,15 +837,14 @@ sub acotan { Math::Complex::acot(@_) } # sub cosh { my ($z) = @_; - my $real; + my $ex; unless (ref $z) { - $z = cplx($z, 0); - $real = 1; + $ex = exp($z); + return ($ex + 1/$ex)/2; } my ($x, $y) = @{$z->cartesian}; - my $ex = exp($x); + $ex = exp($x); my $ex_1 = 1 / $ex; - return cplx(0.5 * ($ex + $ex_1), 0) if $real; return (ref $z)->make(cos($y) * ($ex + $ex_1)/2, sin($y) * ($ex - $ex_1)/2); } @@ -816,15 +856,14 @@ sub cosh { # sub sinh { my ($z) = @_; - my $real; + my $ex; unless (ref $z) { - $z = cplx($z, 0); - $real = 1; + $ex = exp($z); + return ($ex - 1/$ex)/2; } my ($x, $y) = @{$z->cartesian}; - my $ex = exp($x); + $ex = exp($x); my $ex_1 = 1 / $ex; - return cplx(0.5 * ($ex - $ex_1), 0) if $real; return (ref $z)->make(cos($y) * ($ex - $ex_1)/2, sin($y) * ($ex + $ex_1)/2); } @@ -894,14 +933,19 @@ sub cotanh { Math::Complex::coth(@_) } # # acosh # -# Computes the arc hyperbolic cosine acosh(z) = log(z +- sqrt(z*z-1)). +# Computes the arc hyperbolic cosine acosh(z) = log(z + sqrt(z*z-1)). # sub acosh { my ($z) = @_; - $z = cplx($z, 0) unless ref $z; + unless (ref $z) { + return log($z + sqrt($z*$z-1)) if $z >= 1; + $z = cplx($z, 0); + } my ($re, $im) = @{$z->cartesian}; - return log($re + sqrt(cplx($re*$re - 1, 0))) - if ($im == 0 && $re < 0); + if ($im == 0) { + return cplx(log($re + sqrt($re*$re - 1)), 0) if $re >= 1; + return cplx(0, atan2(sqrt(1-$re*$re), $re)) if abs($re) <= 1; + } return log($z + sqrt($z*$z - 1)); } @@ -912,7 +956,6 @@ sub acosh { # sub asinh { my ($z) = @_; - $z = cplx($z, 0) unless ref $z; return log($z + sqrt($z*$z + 1)); } @@ -923,14 +966,13 @@ sub asinh { # sub atanh { my ($z) = @_; + unless (ref $z) { + return log((1 + $z)/(1 - $z))/2 if abs($z) < 1; + $z = cplx($z, 0); + } _divbyzero 'atanh(1)', "1 - $z" if ($z == 1); _logofzero 'atanh(-1)' if ($z == -1); - $z = cplx($z, 0) unless ref $z; - my ($re, $im) = @{$z->cartesian}; - if ($im == 0 && $re > 1) { - return cplx(atanh(1 / $re), pi/2); - } - return log((1 + $z) / (1 - $z)) / 2; + return 0.5 * log((1 + $z) / (1 - $z)); } # @@ -941,12 +983,6 @@ sub atanh { sub asech { my ($z) = @_; _divbyzero 'asech(0)', $z if ($z == 0); - $z = cplx($z, 0) unless ref $z; - my ($re, $im) = @{$z->cartesian}; - if ($im == 0 && $re < 0) { - my $ire = 1 / $re; - return log($ire + sqrt(cplx($ire*$ire - 1, 0))); - } return acosh(1 / $z); } @@ -975,13 +1011,12 @@ sub acosech { Math::Complex::acsch(@_) } # sub acoth { my ($z) = @_; + unless (ref $z) { + return log(($z + 1)/($z - 1))/2 if abs($z) > 1; + $z = cplx($z, 0); + } _divbyzero 'acoth(1)', "$z - 1" if ($z == 1); _logofzero 'acoth(-1)' if ($z == -1); - $z = cplx($z, 0) unless ref $z; - my ($re, $im) = @{$z->cartesian}; - if ($im == 0 and abs($re) < 1) { - return cplx(acoth(1/$re) , pi/2); - } return log((1 + $z) / ($z - 1)) / 2; } @@ -999,17 +1034,23 @@ sub acotanh { Math::Complex::acoth(@_) } # sub atan2 { my ($z1, $z2, $inverted) = @_; - my ($re1, $im1) = ref $z1 ? @{$z1->cartesian} : ($z1, 0); - my ($re2, $im2) = ref $z2 ? @{$z2->cartesian} : ($z2, 0); - my $tan; - if (defined $inverted && $inverted) { # atan(z2/z1) - return pi * ($re2 > 0 ? 1 : -1) if $re1 == 0 && $im1 == 0; - $tan = $z2 / $z1; + my ($re1, $im1, $re2, $im2); + if ($inverted) { + ($re1, $im1) = ref $z2 ? @{$z2->cartesian} : ($z2, 0); + ($re2, $im2) = @{$z1->cartesian}; } else { - return pi * ($re1 > 0 ? 1 : -1) if $re2 == 0 && $im2 == 0; - $tan = $z1 / $z2; + ($re1, $im1) = @{$z1->cartesian}; + ($re2, $im2) = ref $z2 ? @{$z2->cartesian} : ($z2, 0); + } + if ($im2 == 0) { + return cplx(atan2($re1, $re2), 0) if $im1 == 0; + return cplx(($im1<=>0) * pip2, 0) if $re2 == 0; } - return atan($tan); + my $w = atan($z1/$z2); + my ($u, $v) = ref $w ? @{$w->cartesian} : ($w, 0); + $u += pi if $re2 < 0; + $u -= pit2 if $u > pi; + return cplx($u, $v); } # @@ -1017,7 +1058,7 @@ sub atan2 { # ->display_format # # Set (fetch if no argument) display format for all complex numbers that -# don't happen to have overrriden it via ->display_format +# don't happen to have overridden it via ->display_format # # When called as a method, this actually sets the display format for # the current object. @@ -1076,16 +1117,17 @@ sub stringify_cartesian { my $z = shift; my ($x, $y) = @{$z->cartesian}; my ($re, $im); + my $eps = 1e-14; - $x = int($x + ($x < 0 ? -1 : 1) * 1e-14) - if int(abs($x)) != int(abs($x) + 1e-14); - $y = int($y + ($y < 0 ? -1 : 1) * 1e-14) - if int(abs($y)) != int(abs($y) + 1e-14); + $x = int($x + ($x < 0 ? -1 : 1) * $eps) + if int(abs($x)) != int(abs($x) + $eps); + $y = int($y + ($y < 0 ? -1 : 1) * $eps) + if int(abs($y)) != int(abs($y) + $eps); - $re = "$x" if abs($x) >= 1e-14; - if ($y == 1) { $im = 'i' } - elsif ($y == -1) { $im = '-i' } - elsif (abs($y) >= 1e-14) { $im = $y . "i" } + $re = "$x" if abs($x) >= $eps; + if ($y == 1) { $im = 'i' } + elsif ($y == -1) { $im = '-i' } + elsif (abs($y) >= $eps) { $im = $y . "i" } my $str = ''; $str = $re if defined $re; @@ -1110,10 +1152,9 @@ sub stringify_polar { return '[0,0]' if $r <= $eps; - my $tpi = 2 * pi; - my $nt = $t / $tpi; - $nt = ($nt - int($nt)) * $tpi; - $nt += $tpi if $nt < 0; # Range [0, 2pi] + my $nt = $t / pit2; + $nt = ($nt - int($nt)) * pit2; + $nt += pit2 if $nt < 0; # Range [0, 2pi] if (abs($nt) <= $eps) { $theta = 0 } elsif (abs(pi-$nt) <= $eps) { $theta = 'pi' } @@ -1131,9 +1172,9 @@ sub stringify_polar { # Okay, number is not a real. Try to identify pi/n and friends... # - $nt -= $tpi if $nt > pi; + $nt -= pit2 if $nt > pi; my ($n, $k, $kpi); - + for ($k = 1, $kpi = pi; $k < 10; $k++, $kpi += pi) { $n = int($kpi / $nt + ($nt > 0 ? 1 : -1) * 0.5); if (abs($kpi/$n - $nt) <= $eps) { @@ -1164,7 +1205,7 @@ Math::Complex - complex numbers and associated mathematical functions =head1 SYNOPSIS use Math::Complex; - + $z = Math::Complex->make(5, 6); $t = 4 - 3*i + $z; $j = cplxe(1, 2*pi/3); @@ -1241,7 +1282,7 @@ between this form and the cartesian form C is immediate: which is also expressed by this formula: - z = rho * exp(i * theta) = rho * (cos theta + i * sin theta) + z = rho * exp(i * theta) = rho * (cos theta + i * sin theta) In other words, it's the projection of the vector onto the I and I axes. Mathematicians call I the I or I and I @@ -1251,8 +1292,8 @@ noted C. The polar notation (also known as the trigonometric representation) is much more handy for performing multiplications and divisions of complex numbers, whilst the cartesian notation is better -suited for additions and substractions. Real numbers are on the I -axis, and therefore I is zero. +suited for additions and subtractions. Real numbers are on the I +axis, and therefore I is zero or I. All the common operations that can be performed on a real number have been defined to work on complex numbers as well, and are merely @@ -1261,8 +1302,8 @@ they keep their natural meaning when there is no imaginary part, provided the number is within their definition set. For instance, the C routine which computes the square root of -its argument is only defined for positive real numbers and yields a -positive real number (it is an application from B to B). +its argument is only defined for non-negative real numbers and yields a +non-negative real number (it is an application from B to B). If we allow it to return a complex number, then it can be extended to negative real numbers to become an application from B to B (the set of complex numbers): @@ -1275,10 +1316,9 @@ the following definition: sqrt(z = [r,t]) = sqrt(r) * exp(i * t/2) -Indeed, a negative real number can be noted C<[x,pi]> -(the modulus I is always positive, so C<[x,pi]> is really C<-x>, a -negative number) -and the above definition states that +Indeed, a negative real number can be noted C<[x,pi]> (the modulus +I is always non-negative, so C<[x,pi]> is really C<-x>, a negative +number) and the above definition states that sqrt([x,pi]) = sqrt(x) * exp(i*pi/2) = [sqrt(x),pi/2] = sqrt(x)*i @@ -1342,7 +1382,6 @@ the following (overloaded) operations are supported on complex numbers: log(z1) = log(r1) + i*t1 sin(z1) = 1/2i (exp(i * z1) - exp(-i * z1)) cos(z1) = 1/2 (exp(i * z1) + exp(-i * z1)) - abs(z1) = r1 atan2(z1, z2) = atan(z1/z2) The following extra operations are supported on both real and complex @@ -1363,7 +1402,7 @@ numbers: cot(z) = 1 / tan(z) asin(z) = -i * log(i*z + sqrt(1-z*z)) - acos(z) = -i * log(z + sqrt(z*z-1)) + acos(z) = -i * log(z + i*sqrt(1-z*z)) atan(z) = i/2 * log((i+z) / (i-z)) acsc(z) = asin(1 / z) @@ -1377,7 +1416,7 @@ numbers: csch(z) = 1 / sinh(z) sech(z) = 1 / cosh(z) coth(z) = 1 / tanh(z) - + asinh(z) = log(z + sqrt(z*z+1)) acosh(z) = log(z + sqrt(z*z-1)) atanh(z) = 1/2 * log((1+z) / (1-z)) @@ -1423,21 +1462,21 @@ if you know the cartesian form of the number, or $z = 3 + 4*i; -if you like. To create a number using the trigonometric form, use either: +if you like. To create a number using the polar form, use either: $z = Math::Complex->emake(5, pi/3); $x = cplxe(5, pi/3); instead. The first argument is the modulus, the second is the angle -(in radians, the full circle is 2*pi). (Mnmemonic: C is used as a -notation for complex numbers in the trigonometric form). +(in radians, the full circle is 2*pi). (Mnemonic: C is used as a +notation for complex numbers in the polar form). It is possible to write: $x = cplxe(-3, pi/4); but that will be silently converted into C<[3,-3pi/4]>, since the modulus -must be positive (it represents the distance to the origin in the complex +must be non-negative (it represents the distance to the origin in the complex plane). =head1 STRINGIFICATION @@ -1534,17 +1573,8 @@ argument cannot be I, where I is any integer. =head1 BUGS Saying C exports many mathematical routines in the -caller environment and even overrides some (C, C, C, -C, C). This is construed as a feature by the Authors, -actually... ;-) - -The code is not optimized for speed, although we try to use the cartesian -form for addition-like operators and the trigonometric form for all -multiplication-like operators. - -The arg() routine does not ensure the angle is within the range [-pi,+pi] -(a side effect caused by multiplication and division using the trigonometric -representation). +caller environment and even overrides some (C, C). +This is construed as a feature by the Authors, actually... ;-) All routines expect to be given real or complex numbers. Don't attempt to use BigFloat, since Perl has currently no rule to disambiguate a '+' @@ -1555,6 +1585,8 @@ operation (for instance) between two overloaded entities. Raphael Manfredi > and Jarkko Hietaniemi >. +Extensive patches by Daniel S. Lewart >. + =cut # eof diff --git a/lib/Sys/Hostname.pm b/lib/Sys/Hostname.pm index d23310a..95f9a99 100644 --- a/lib/Sys/Hostname.pm +++ b/lib/Sys/Hostname.pm @@ -78,6 +78,19 @@ sub hostname { syscall(&main::SYS_gethostname, $host, 65) == 0; } + # method 2a - syscall using systeminfo instead of gethostname + # -- needed on systems like Solaris + || eval { + local $SIG{__DIE__}; + { + package main; + require "sys/syscall.ph"; + require "sys/systeminfo.ph"; + } + $host = "\0" x 65; ## preload scalar + syscall(&main::SYS_systeminfo, &main::SI_HOSTNAME, $host, 65) != -1; + } + # method 3 - trusty old hostname command || eval { local $SIG{__DIE__}; diff --git a/lib/Sys/Syslog.pm b/lib/Sys/Syslog.pm index f6d9c35..709f578 100644 --- a/lib/Sys/Syslog.pm +++ b/lib/Sys/Syslog.pm @@ -54,15 +54,16 @@ is replaced with C<"$!"> (the latest error message). Sets log mask I<$mask_priority> and returns the old mask. -=item setlogsock $sock_type +=item setlogsock $sock_type (added in 5.004_03) Sets the socket type to be used for the next call to C or C. -A value of 'unix' will connect to the UNIX domain socket returned -by C<_PATH_LOG> in F. A value of 'inet' will connect -to an INET socket returned by getservbyname(). -Any other value croaks. +A value of 'unix' will connect to the UNIX domain socket returned by +C<_PATH_LOG> in F. If F fails to define +C<_PATH_LOG>, C returns C; otherwise a true value is +returned. A value of 'inet' will connect to an INET socket returned by +getservbyname(). Any other value croaks. The default is for the INET socket to be used. @@ -135,12 +136,17 @@ sub setlogmask { sub setlogsock { local($setsock) = shift; if (lc($setsock) eq 'unix') { - $sock_unix = 1; + if (defined &_PATH_LOG) { + $sock_unix = 1; + } else { + return undef; + } } elsif (lc($setsock) eq 'inet') { undef($sock_unix); } else { croak "Invalid argument passed to setlogsock; must be 'unix' or 'inet'"; } + return 1; } sub syslog { diff --git a/lib/Test/Harness.pm b/lib/Test/Harness.pm index 24e9148..f5fc3d8 100644 --- a/lib/Test/Harness.pm +++ b/lib/Test/Harness.pm @@ -19,11 +19,11 @@ $VERSION = "1.1502"; format STDOUT_TOP = Failed Test Status Wstat Total Fail Failed List of failed ------------------------------------------------------------------------------- +------------------------------------------------------------------------------- . format STDOUT = -@<<<<<<<<<<<<<< @>> @>>>> @>>>> @>>> ^##.##% @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< +@<<<<<<<<<<<<<< @>> @>>>> @>>>> @>>> ^##.##% ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< { $curtest->{name}, $curtest->{estat}, $curtest->{wstat}, @@ -32,6 +32,8 @@ format STDOUT = $curtest->{percent}, $curtest->{canon} } +~~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + $curtest->{canon} . @@ -110,7 +112,8 @@ sub runtests { : $wstatus >> 8); if ($wstatus) { my ($failed, $canon, $percent) = ('??', '??'); - print "dubious\n\tTest returned status $estatus (wstat $wstatus)\n"; + printf "dubious\n\tTest returned status $estatus (wstat %d, 0x%x)\n", + $wstatus,$wstatus; print "\t\t(VMS status is $estatus)\n" if $^O eq 'VMS'; if (corestatus($wstatus)) { # until we have a wait module if ($have_devel_corestack) { @@ -321,6 +324,10 @@ The global variable $Test::Harness::verbose is exportable and can be used to let runtests() display the standard output of the script without altering the behavior otherwise. +The global variable $Test::Harness::switches is exportable and can be +used to set perl command line options used for running the test +script(s). The default value is C<-w>. + =head1 EXPORT C<&runtests> is exported by Test::Harness per default. diff --git a/lib/Time/Local.pm b/lib/Time/Local.pm index d2d70da..eef412d 100644 --- a/lib/Time/Local.pm +++ b/lib/Time/Local.pm @@ -107,7 +107,9 @@ sub cheat { @g = gmtime($guess); $year += $YearFix if $year < $epoch; $lastguess = ""; + $counter = 0; while ($diff = $year - $g[5]) { + croak "Can't handle date (".join(", ",@_).")" if ++$counter > 255; $guess += $diff * (363 * $DAY); @g = gmtime($guess); if (($thisguess = "@g") eq $lastguess){ @@ -116,6 +118,7 @@ sub cheat { $lastguess = $thisguess; } while ($diff = $month - $g[4]) { + croak "Can't handle date (".join(", ",@_).")" if ++$counter > 255; $guess += $diff * (27 * $DAY); @g = gmtime($guess); if (($thisguess = "@g") eq $lastguess){ diff --git a/lib/autouse.pm b/lib/autouse.pm index a15d08a..ab95a19 100644 --- a/lib/autouse.pm +++ b/lib/autouse.pm @@ -49,9 +49,9 @@ sub import { } my $load_sub = sub { - unless ($INC{pm}) { - require $pm; - die $@ if $@; + unless ($INC{$pm}) { + eval {require $pm}; + die if $@; vet_import $module; } *$closure_import_func = \&{"${module}::$closure_func"}; @@ -73,7 +73,7 @@ sub vet_import ($) { my $module = shift; if (my $import = $module->can('import')) { croak "autoused module has unique import() method" - unless defined(\&Exporter::import) + unless defined(&Exporter::import) && $import == \&Exporter::import; } } diff --git a/lib/base.pm b/lib/base.pm new file mode 100644 index 0000000..e20a64b --- /dev/null +++ b/lib/base.pm @@ -0,0 +1,49 @@ +=head1 NAME + +base - Establish IS-A relationship with base class at compile time + +=head1 SYNOPSIS + + package Baz; + + use base qw(Foo Bar); + +=head1 DESCRIPTION + +Roughly similar in effect to + + BEGIN { + require Foo; + require Bar; + push @ISA, qw(Foo Bar); + } + +This module was introduced with Perl 5.004_04. + +=head1 BUGS + +Needs proper documentation! + +=cut + +package base; + +sub import { + my $class = shift; + + foreach my $base (@_) { + unless (defined %{"$base\::"}) { + eval "require $base"; + unless (defined %{"$base\::"}) { + require Carp; + Carp::croak("Base class package \"$base\" is empty.\n", + "\t(Perhaps you need to 'use' the module ", + "which defines that package first.)"); + } + } + } + + push @{caller(0) . '::ISA'}, @_; +} + +1; diff --git a/lib/blib.pm b/lib/blib.pm index 2dd7802..9e0f6c0 100644 --- a/lib/blib.pm +++ b/lib/blib.pm @@ -47,7 +47,6 @@ sub import my $dir = getcwd; if (@_) { - print join(',',@_),"\n"; $dir = shift; $dir =~ s/blib$//; $dir =~ s,/+$,,; diff --git a/lib/diagnostics.pm b/lib/diagnostics.pm old mode 100644 new mode 100755 index 10016f3..78bf445 --- a/lib/diagnostics.pm +++ b/lib/diagnostics.pm @@ -175,6 +175,8 @@ if ($^O eq 'VMS') { @trypod = ("$archlib/pod/perldiag.pod", "$privlib/pod/perldiag-$].pod", "$privlib/pod/perldiag.pod"); +# handy for development testing of new warnings etc +unshift @trypod, "./pod/perldiag.pod" if -e "pod/perldiag.pod"; ($PODFILE) = ((grep { -e } @trypod), $trypod[$#trypod])[0]; $DEBUG ||= 0; diff --git a/lib/getopt.pl b/lib/getopt.pl index a6023c8..f871e41 100644 --- a/lib/getopt.pl +++ b/lib/getopt.pl @@ -24,10 +24,10 @@ sub Getopt { shift(@ARGV); $rest = shift(@ARGV); } - eval "\$opt_$first = \$rest;"; + ${"opt_$first"} = $rest; } else { - eval "\$opt_$first = 1;"; + ${"opt_$first"} = 1; if ($rest ne '') { $ARGV[0] = "-$rest"; } diff --git a/lib/perl5db.pl b/lib/perl5db.pl index 469ebff..d5dbfbd 100644 --- a/lib/perl5db.pl +++ b/lib/perl5db.pl @@ -2,7 +2,7 @@ package DB; # Debugger for Perl 5.00x; perl5db.pl patch level: -$VERSION = 1.00; +$VERSION = 1.01; $header = "perl5db.pl version $VERSION"; # Enhanced by ilya@math.ohio-state.edu (Ilya Zakharevich) @@ -808,9 +808,11 @@ sub DB { last CMD; }; $cmd =~ /^c\b\s*([\w:]*)\s*$/ && do { end_report(), next CMD if $finished and $level <= 1; - $i = $1; + $subname = $i = $1; if ($i =~ /\D/) { # subroutine name - ($file,$i) = (find_sub($i) =~ /^(.*):(.*)$/); + $subname = $package."::".$subname + unless $subname =~ /::/; + ($file,$i) = (find_sub($subname) =~ /^(.*):(.*)$/); $i += 0; if ($i) { $filename = $file; @@ -1128,7 +1130,11 @@ sub sub { $doret = -2 if $doret eq $#stack or $frame & 16; @ret; } else { - $ret = &$sub; + if (defined wantarray) { + $ret = &$sub; + } else { + &$sub; undef $ret; + }; $single |= pop(@stack); ($frame & 4 ? ( (print $LINEINFO ' ' x $#stack, "out "), @@ -1178,8 +1184,8 @@ sub postponed_sub { my $offset = $1 || 0; # Filename below can contain ':' my ($file,$i) = (find_sub($subname) =~ /^(.*):(\d+)-.*$/); - $i += $offset; if ($i) { + $i += $offset; local *dbline = $main::{'_<' . $file}; local $^W = 0; # != 0 is magical below $had_breakpoints{$file}++; @@ -1822,18 +1828,15 @@ sub dbwarn { local $doret = -2; local $SIG{__WARN__} = ''; local $SIG{__DIE__} = ''; - eval { require Carp }; # If error/warning during compilation, - # require may be broken. - warn(@_, "\nPossible unrecoverable error"), warn("\nTry to decrease warnLevel `O'ption!\n"), return - unless defined &Carp::longmess; - #&warn("Entering dbwarn\n"); + eval { require Carp } if defined $^S; # If error/warning during compilation, + # require may be broken. + warn(@_, "\nCannot print stack trace, load with -MCarp option to see stack"), + return unless defined &Carp::longmess; my ($mysingle,$mytrace) = ($single,$trace); $single = 0; $trace = 0; my $mess = Carp::longmess(@_); ($single,$trace) = ($mysingle,$mytrace); - #&warn("Warning in dbwarn\n"); &warn($mess); - #&warn("Exiting dbwarn\n"); } sub dbdie { @@ -1842,28 +1845,24 @@ sub dbdie { local $SIG{__DIE__} = ''; local $SIG{__WARN__} = ''; my $i = 0; my $ineval = 0; my $sub; - #&warn("Entering dbdie\n"); - if ($dieLevel != 2) { - while ((undef,undef,undef,$sub) = caller(++$i)) { - $ineval = 1, last if $sub eq '(eval)'; - } - { + if ($dieLevel > 2) { local $SIG{__WARN__} = \&dbwarn; - &warn(@_) if $dieLevel > 2; # Ineval is false during destruction? - } - #&warn("dieing quietly in dbdie\n") if $ineval and $dieLevel < 2; - die @_ if $ineval and $dieLevel < 2; + &warn(@_); # Yell no matter what + return; + } + if ($dieLevel < 2) { + die @_ if $^S; # in eval propagate } - eval { require Carp }; # If error/warning during compilation, - # require may be broken. - die(@_, "\nUnrecoverable error") unless defined &Carp::longmess; + eval { require Carp } if defined $^S; # If error/warning during compilation, + # require may be broken. + die(@_, "\nCannot print stack trace, load with -MCarp option to see stack") + unless defined &Carp::longmess; # We do not want to debug this chunk (automatic disabling works # inside DB::DB, but not in Carp). my ($mysingle,$mytrace) = ($single,$trace); $single = 0; $trace = 0; my $mess = Carp::longmess(@_); ($single,$trace) = ($mysingle,$mytrace); - #&warn("dieing loudly in dbdie\n"); die $mess; } diff --git a/lib/vars.pm b/lib/vars.pm index e007baa..5723ac6 100644 --- a/lib/vars.pm +++ b/lib/vars.pm @@ -1,5 +1,39 @@ package vars; +require 5.002; + +# The following require can't be removed during maintenance +# releases, sadly, because of the risk of buggy code that does +# require Carp; Carp::croak "..."; without brackets dying +# if Carp hasn't been loaded in earlier compile time. :-( +# We'll let those bugs get found on the development track. +require Carp if $] < 5.00450; + +sub import { + my $callpack = caller; + my ($pack, @imports, $sym, $ch) = @_; + foreach $sym (@imports) { + if ($sym =~ /::/) { + require Carp; + Carp::croak("Can't declare another package's variables"); + } + ($ch, $sym) = unpack('a1a*', $sym); + *{"${callpack}::$sym"} = + ( $ch eq "\$" ? \$ {"${callpack}::$sym"} + : $ch eq "\@" ? \@ {"${callpack}::$sym"} + : $ch eq "\%" ? \% {"${callpack}::$sym"} + : $ch eq "\*" ? \* {"${callpack}::$sym"} + : $ch eq "\&" ? \& {"${callpack}::$sym"} + : do { + require Carp; + Carp::croak("'$ch$sym' is not a valid variable name\n"); + }); + } +}; + +1; +__END__ + =head1 NAME vars - Perl pragma to predeclare global variable names @@ -30,24 +64,3 @@ later-loaded routines. See L. =cut - -require 5.002; -use Carp; - -sub import { - my $callpack = caller; - my ($pack, @imports, $sym, $ch) = @_; - foreach $sym (@imports) { - croak "Can't declare another package's variables" if $sym =~ /::/; - ($ch, $sym) = unpack('a1a*', $sym); - *{"${callpack}::$sym"} = - ( $ch eq "\$" ? \$ {"${callpack}::$sym"} - : $ch eq "\@" ? \@ {"${callpack}::$sym"} - : $ch eq "\%" ? \% {"${callpack}::$sym"} - : $ch eq "\*" ? \* {"${callpack}::$sym"} - : $ch eq "\&" ? \& {"${callpack}::$sym"} - : croak "'$ch$sym' is not a valid variable name\n"); - } -}; - -1; diff --git a/makedepend.SH b/makedepend.SH index 89f650d..7a89fa9 100755 --- a/makedepend.SH +++ b/makedepend.SH @@ -28,6 +28,12 @@ MAKE=$make !GROK!THIS! $spitshell >>makedepend <<'!NO!SUBS!' +# This script should be called with +# sh ./makedepend MAKE=$(MAKE) +case "$1" in + MAKE=*) eval $1 ;; +esac + export PATH || (echo "OOPS, this isn't sh. Desperation time. I will feed myself to sh."; sh \$0; kill \$\$) case $CONFIG in @@ -112,6 +118,7 @@ for file in `$cat .clist`; do $cppstdin $finc -I/usr/local/include -I. $cppflags $cppminus /d' \ + -e '/^#.*"-"/d' \ -e 's#\.[0-9][0-9]*\.c#'"$file.c#" \ -e 's/^[ ]*#[ ]*line/#/' \ -e '/^# *[0-9][0-9]* *[".\/]/!d' \ diff --git a/malloc.c b/malloc.c index c84db66..e8e9ca3 100644 --- a/malloc.c +++ b/malloc.c @@ -649,8 +649,8 @@ realloc(mp, nbytes) #ifdef PERL_CORE #ifdef DEBUGGING if (debug & 128) { - PerlIO_printf(PerlIO_stderr(), "0x%lx: (%05lu) rfree\n",(unsigned long)res,(unsigned long)(an++)); - PerlIO_printf(PerlIO_stderr(), "0x%lx: (%05lu) realloc %ld bytes\n", + PerlIO_printf(Perl_debug_log, "0x%lx: (%05lu) rfree\n",(unsigned long)res,(unsigned long)(an++)); + PerlIO_printf(Perl_debug_log, "0x%lx: (%05lu) realloc %ld bytes\n", (unsigned long)res,(unsigned long)(an++),(long)size); } #endif @@ -814,7 +814,7 @@ int size; } #ifdef PERL_CORE - DEBUG_m(PerlIO_printf(PerlIO_stderr(), "sbrk malloc size %ld (reqsize %ld), left size %ld, give addr 0x%lx\n", + DEBUG_m(PerlIO_printf(Perl_debug_log, "sbrk malloc size %ld (reqsize %ld), left size %ld, give addr 0x%lx\n", size, reqsize, Perl_sbrk_oldsize, got)); #endif diff --git a/mg.c b/mg.c index 7c7ea2a..ee87d47 100644 --- a/mg.c +++ b/mg.c @@ -357,8 +357,15 @@ MAGIC *mg; } #else #ifdef OS2 - sv_setnv(sv, (double)Perl_rc); - sv_setpv(sv, os2error(Perl_rc)); + if (!(_emx_env & 0x200)) { /* Under DOS */ + sv_setnv(sv, (double)errno); + sv_setpv(sv, errno ? Strerror(errno) : ""); + } else { + if (errno != errno_isOS2) + Perl_rc = _syserrno(); + sv_setnv(sv, (double)Perl_rc); + sv_setpv(sv, os2error(Perl_rc)); + } #else sv_setnv(sv, (double)errno); sv_setpv(sv, errno ? Strerror(errno) : ""); @@ -384,6 +391,14 @@ MAGIC *mg; case '\020': /* ^P */ sv_setiv(sv, (IV)perldb); break; + case '\023': /* ^S */ + if (lex_state != LEX_NOTPARSING) + SvOK_off(sv); + else if (in_eval) + sv_setiv(sv, 1); + else + sv_setiv(sv, 0); + break; case '\024': /* ^T */ #ifdef BIG_TIME sv_setnv(sv, basetime); @@ -654,6 +669,28 @@ MAGIC* mg; } int +magic_set_all_env(sv,mg) +SV* sv; +MAGIC* mg; +{ +#if defined(VMS) + die("Can't make list assignment to %%ENV on this system"); +#else + if (localizing) { + HE* entry; + magic_clear_all_env(sv,mg); + hv_iterinit((HV*)sv); + while (entry = hv_iternext((HV*)sv)) { + I32 keylen; + my_setenv(hv_iterkey(entry, &keylen), + SvPV(hv_iterval((HV*)sv, entry), na)); + } + } +#endif + return 0; +} + +int magic_clear_all_env(sv,mg) SV* sv; MAGIC* mg; @@ -1601,16 +1638,28 @@ MAGIC* mg; s += strlen(s); /* See if all the arguments are contiguous in memory */ for (i = 1; i < origargc; i++) { - if (origargv[i] == s + 1) + if (origargv[i] == s + 1 +#ifdef OS2 + || origargv[i] == s + 2 +#endif + ) s += strlen(++s); /* this one is ok too */ + else + break; } /* can grab env area too? */ - if (origenviron && origenviron[0] == s + 1) { + if (origenviron && (origenviron[0] == s + 1 +#ifdef OS2 + || (origenviron[0] == s + 9 && (s += 8)) +#endif + )) { my_setenv("NoNe SuCh", Nullch); /* force copy of environment */ for (i = 0; origenviron[i]; i++) if (origenviron[i] == s + 1) s += strlen(++s); + else + break; } origalen = s - origargv[0]; } @@ -1618,9 +1667,11 @@ MAGIC* mg; i = len; if (i >= origalen) { i = origalen; - SvCUR_set(sv, i); - *SvEND(sv) = '\0'; + /* don't allow system to limit $0 seen by script */ + /* SvCUR_set(sv, i); *SvEND(sv) = '\0'; */ Copy(s, origargv[0], i, char); + s = origargv[0]+i; + *s = '\0'; } else { Copy(s, origargv[0], i, char); diff --git a/miniperlmain.c b/miniperlmain.c index 680b042..402f2ef 100644 --- a/miniperlmain.c +++ b/miniperlmain.c @@ -2,6 +2,10 @@ * "The Road goes ever on and on, down from the door where it began." */ +#ifdef OEMVS +#pragma runopts(HEAP(1M,32K,ANYWHERE,KEEP,8K,4K)) +#endif + #ifdef __cplusplus extern "C" { #endif diff --git a/myconfig b/myconfig index 5beb42a..86da2ed 100755 --- a/myconfig +++ b/myconfig @@ -31,7 +31,7 @@ Summary of my $package ($baserev patchlevel $PATCHLEVEL subversion $SUBVERSION) ccflags ='$ccflags' stdchar='$stdchar', d_stdstdio=$d_stdstdio, usevfork=$usevfork voidflags=$voidflags, castflags=$castflags, d_casti32=$d_casti32, d_castneg=$d_castneg - intsize=$intsize, alignbytes=$alignbytes, usemymalloc=$usemymalloc, randbits=$randbits + intsize=$intsize, alignbytes=$alignbytes, usemymalloc=$usemymalloc, prototype=$prototype Linker and Libraries: ld='$ld', ldflags ='$ldflags' libpth=$libpth diff --git a/op.c b/op.c index feae588..8e8811d 100644 --- a/op.c +++ b/op.c @@ -125,7 +125,7 @@ char *name; } croak("Can't use global %s in \"my\"",name); } - if (AvFILL(comppad_name) >= 0) { + if (dowarn && AvFILL(comppad_name) >= 0) { SV **svp = AvARRAY(comppad_name); for (off = AvFILL(comppad_name); off > comppad_name_floor; off--) { if ((sv = svp[off]) @@ -2771,7 +2771,8 @@ OP *block; if (expr) { if (once && expr->op_type == OP_CONST && !SvTRUE(((SVOP*)expr)->op_sv)) return block; /* do {} while 0 does once */ - if (expr->op_type == OP_READLINE || expr->op_type == OP_GLOB) { + if (expr->op_type == OP_READLINE || expr->op_type == OP_GLOB + || (expr->op_type == OP_NULL && expr->op_targ == OP_GLOB)) { expr = newUNOP(OP_DEFINED, 0, newASSIGNOP(0, newSVREF(newGVOP(OP_GV, 0, defgv)), 0, expr) ); } @@ -2795,10 +2796,11 @@ OP *block; } OP * -newWHILEOP(flags, debuggable, loop, expr, block, cont) +newWHILEOP(flags, debuggable, loop, whileline, expr, block, cont) I32 flags; I32 debuggable; LOOP *loop; +I32 whileline; OP *expr; OP *block; OP *cont; @@ -2809,7 +2811,8 @@ OP *cont; OP *op; OP *condop; - if (expr && (expr->op_type == OP_READLINE || expr->op_type == OP_GLOB)) { + if (expr && (expr->op_type == OP_READLINE || expr->op_type == OP_GLOB + || (expr->op_type == OP_NULL && expr->op_targ == OP_GLOB))) { expr = newUNOP(OP_DEFINED, 0, newASSIGNOP(0, newSVREF(newGVOP(OP_GV, 0, defgv)), 0, expr) ); } @@ -2819,8 +2822,14 @@ OP *cont; if (cont) next = LINKLIST(cont); - if (expr) + if (expr) { cont = append_elem(OP_LINESEQ, cont, newOP(OP_UNSTACK, 0)); + if ((line_t)whileline != NOLINE) { + copline = whileline; + cont = append_elem(OP_LINESEQ, cont, + newSTATEOP(0, Nullch, Nullop)); + } + } listop = append_list(OP_LINESEQ, (LISTOP*)block, (LISTOP*)cont); redo = LINKLIST(listop); @@ -2878,10 +2887,10 @@ newFOROP(I32 flags,char *label,line_t forline,OP *sv,OP *expr,OP *block,OP *cont #endif /* CAN_PROTOTYPE */ { LOOP *loop; + OP *wop; int padoff = 0; I32 iterflags = 0; - copline = forline; if (sv) { if (sv->op_type == OP_RV2SV) { /* symbol table variable */ sv->op_type = OP_RV2GV; @@ -2908,8 +2917,9 @@ newFOROP(I32 flags,char *label,line_t forline,OP *sv,OP *expr,OP *block,OP *cont assert(!loop->op_next); Renew(loop, 1, LOOP); loop->op_targ = padoff; - return newSTATEOP(0, label, newWHILEOP(flags, 1, loop, - newOP(OP_ITER, 0), block, cont)); + wop = newWHILEOP(flags, 1, loop, forline, newOP(OP_ITER, 0), block, cont); + copline = forline; + return newSTATEOP(0, label, wop); } OP* @@ -2993,7 +3003,7 @@ CV* cv; SV** ppad; I32 ix; - PerlIO_printf(Perl_debug_log, "\tCV=0x%p (%s), OUTSIDE=0x%p (%s)\n", + PerlIO_printf(Perl_debug_log, "\tCV=0x%lx (%s), OUTSIDE=0x%lx (%s)\n", cv, (CvANON(cv) ? "ANON" : (cv == main_cv) ? "MAIN" @@ -3016,7 +3026,7 @@ CV* cv; for (ix = 1; ix <= AvFILL(pad_name); ix++) { if (SvPOK(pname[ix])) - PerlIO_printf(Perl_debug_log, "\t%4d. 0x%p (%s\"%s\" %ld-%ld)\n", + PerlIO_printf(Perl_debug_log, "\t%4d. 0x%lx (%s\"%s\" %ld-%ld)\n", ix, ppad[ix], SvFAKE(pname[ix]) ? "FAKE " : "", SvPVX(pname[ix]), @@ -3791,7 +3801,7 @@ OP *op; if (cLISTOP->op_first->op_type == OP_STUB) { op_free(op); op = newUNOP(type, OPf_SPECIAL, - newGVOP(OP_GV, 0, gv_fetchpv("main'ARGV", TRUE, SVt_PVAV))); + newGVOP(OP_GV, 0, gv_fetchpv("main::ARGV", TRUE, SVt_PVAV))); } return ck_fun(op); } @@ -3962,7 +3972,7 @@ OP *op; else { op_free(op); if (type == OP_FTTTY) - return newGVOP(type, OPf_REF, gv_fetchpv("main'STDIN", TRUE, + return newGVOP(type, OPf_REF, gv_fetchpv("main::STDIN", TRUE, SVt_PVIO)); else return newUNOP(type, 0, newSVREF(newGVOP(OP_GV, 0, defgv))); @@ -4112,7 +4122,13 @@ OP * ck_glob(op) OP *op; { - GV *gv = gv_fetchpv("glob", FALSE, SVt_PVCV); + GV *gv; + + if ((op->op_flags & OPf_KIDS) && !cLISTOP->op_first->op_sibling) + append_elem(OP_GLOB, op, newSVREF(newGVOP(OP_GV, 0, defgv))); + + if (!((gv = gv_fetchpv("glob", FALSE, SVt_PVCV)) && GvIMPORTED_CV(gv))) + gv = gv_fetchpv("CORE::GLOBAL::glob", FALSE, SVt_PVCV); if (gv && GvIMPORTED_CV(gv)) { static int glob_index; @@ -4127,10 +4143,10 @@ OP *op; append_elem(OP_LIST, op, scalar(newUNOP(OP_RV2CV, 0, newGVOP(OP_GV, 0, gv))))); - return ck_subr(op); + op = newUNOP(OP_NULL, 0, ck_subr(op)); + op->op_targ = OP_GLOB; /* hint at what it used to be */ + return op; } - if ((op->op_flags & OPf_KIDS) && !cLISTOP->op_first->op_sibling) - append_elem(OP_GLOB, op, newSVREF(newGVOP(OP_GV, 0, defgv))); gv = newGVgen("main"); gv_IOadd(gv); append_elem(OP_GLOB, op, newGVOP(OP_GV, 0, gv)); @@ -4617,7 +4633,8 @@ OP *op; prev = o; o = o->op_sibling; } - if (proto && !optional && *proto == '$') + if (proto && !optional && + (*proto && *proto != '@' && *proto != '%' && *proto != ';')) return too_few_arguments(op, gv_ename(namegv)); return op; } diff --git a/opcode.h b/opcode.h index bdcf5f6..d962c1d 100644 --- a/opcode.h +++ b/opcode.h @@ -2252,7 +2252,7 @@ EXT U32 opargs[] = { 0x0001111c, /* vec */ 0x0009111c, /* index */ 0x0009111c, /* rindex */ - 0x0000210d, /* sprintf */ + 0x0000210f, /* sprintf */ 0x00002105, /* formline */ 0x0000099e, /* ord */ 0x0000098e, /* chr */ diff --git a/os2/Changes b/os2/Changes index 146ce87..4e0c4d4 100644 --- a/os2/Changes +++ b/os2/Changes @@ -158,3 +158,8 @@ before 5.004_02: will work. Perl will also look in the current directory first. Moreover, a bug with \; in PATH being non-separator is fixed. +after 5.004_03: + $^E tracks calls to CRT now. (May break if Perl masks some + changes to errno?) + $0 may be edited to longer lengths (at least under OS/2). + OS2::REXX->loads looks in the OS/2-ish fashion too. diff --git a/os2/OS2/REXX/Makefile.PL b/os2/OS2/REXX/Makefile.PL index c27cb0d..0b43a36 100644 --- a/os2/OS2/REXX/Makefile.PL +++ b/os2/OS2/REXX/Makefile.PL @@ -2,7 +2,7 @@ use ExtUtils::MakeMaker; WriteMakefile( NAME => 'OS2::REXX', - VERSION => '0.2', + VERSION => '0.21', MAN3PODS => ' ', # Pods will be built by installman. XSPROTOARG => '-noprototypes', ); diff --git a/os2/OS2/REXX/REXX.pm b/os2/OS2/REXX/REXX.pm index 114e159..4580ede 100644 --- a/os2/OS2/REXX/REXX.pm +++ b/os2/OS2/REXX/REXX.pm @@ -39,6 +39,7 @@ sub load $handle = DynaLoader::dl_load_file("$_/$file.dll"); last if $handle; } + $handle = DynaLoader::dl_load_file($file) unless $handle; return undef unless $handle; eval "package OS2::REXX::$file; \@ISA = ('OS2::REXX');" . "sub AUTOLOAD {" @@ -244,7 +245,8 @@ variables may be usable even without C though. NAME is DLL name, without path and extension. Directories are searched WHERE first (list of dirs), then environment -paths PERL5REXX, PERLREXX or, as last resort, PATH. +paths PERL5REXX, PERLREXX, PATH or, as last resort, OS/2-ish search +is performed in default DLL path (without adding paths and extensions). The DLL is not unloaded when the variable dies. diff --git a/os2/os2.c b/os2/os2.c index 8074242..8a292e3 100644 --- a/os2/os2.c +++ b/os2/os2.c @@ -294,7 +294,7 @@ int execf; register char *s; char flags[10]; char *shell, *copt, *news = NULL; - int rc, added_shell = 0, err; + int rc, added_shell = 0, err, seenspace = 0; char fullcmd[MAXNAMLEN + 1]; #ifdef TRYSHELL @@ -346,6 +346,8 @@ int execf; if (*s == '\n' && s[1] == '\0') { *s = '\0'; break; + } else if (*s == '\\' && !seenspace) { + continue; /* Allow backslashes in names */ } doshell: if (execf == EXECF_TRUEEXEC) @@ -364,6 +366,8 @@ int execf; if (rc < 0) rc = 255 << 8; /* Emulate the fork(). */ if (news) Safefree(news); return rc; + } else if (*s == ' ' || *s == '\t') { + seenspace = 1; } } diff --git a/patchlevel.h b/patchlevel.h index 7881ec9..2adaed5 100644 --- a/patchlevel.h +++ b/patchlevel.h @@ -1,9 +1,9 @@ #define PATCHLEVEL 4 -#define SUBVERSION 3 +#define SUBVERSION 4 /* local_patches -- list of locally applied less-than-subversion patches. - If you're distributing such a patch, please give it a name and a + If you're distributing such a patch, please give it a tag name and a one-line description, placed just before the last NULL in the array below. If your patch fixes a bug in the perlbug database, please mention the bugid. If your patch *IS* dependent on a prior patch, @@ -17,7 +17,7 @@ --- patchlevel.h *** 38,43 *** --- 38,44 --- - ,"FOO1235 - some patch" + ,"MAINT_TRIAL_1 - 5.00x_0x maintenance release trial 1" ,"BAR3141 - another patch" ,"BAZ2718 - and another patch" + ,"MINE001 - my new patch" @@ -36,6 +36,7 @@ This will prevent patch from choking if someone has previously applied different patches than you. */ +/* The following line and terminating '};' are read by perlbug.PL. Don't alter. */ static char *local_patches[] = { NULL ,NULL diff --git a/perl.c b/perl.c index 69b5c0e..7df632d 100644 --- a/perl.c +++ b/perl.c @@ -144,6 +144,7 @@ register PerlInterpreter *sv_interp; #endif init_ids(); + lex_state = LEX_NOTPARSING; start_env.je_prev = NULL; start_env.je_ret = -1; @@ -605,20 +606,23 @@ setuid perl scripts securely.\n"); croak("No code specified for -e"); (void)PerlIO_putc(e_fp,'\n'); break; - case 'I': + case 'I': /* -I handled both here and in moreswitches() */ forbid_setid("-I"); - sv_catpv(sv,"-"); - sv_catpv(sv,s); - sv_catpv(sv," "); - if (*++s) { - incpush(s, TRUE); - } - else if (argv[1]) { - incpush(argv[1], TRUE); - sv_catpv(sv,argv[1]); + if (!*++s && (s=argv[1]) != Nullch) { argc--,argv++; - sv_catpv(sv," "); } + while (s && isSPACE(*s)) + ++s; + if (s && *s) { + char *e, *p; + for (e = s; *e && !isSPACE(*e); e++) ; + p = savepvn(s, e-s); + incpush(p, TRUE); + sv_catpv(sv,"-I"); + sv_catpv(sv,p); + sv_catpv(sv," "); + Safefree(p); + } /* XXX else croak? */ break; case 'P': forbid_setid("-P"); @@ -693,22 +697,24 @@ print \" \\@INC:\\n @INC\\n\";"); if (*s) cddir = savepv(s); break; - case '-': - if (*++s) { /* catch use of gnu style long options */ - if (strEQ(s, "version")) { - s = "v"; - goto reswitch; - } - if (strEQ(s, "help")) { - s = "h"; - goto reswitch; - } - croak("Unrecognized switch: --%s (-h will show valid options)",s); - } - argc--,argv++; - goto switch_end; case 0: break; + case '-': + if (!*++s || isSPACE(*s)) { + argc--,argv++; + goto switch_end; + } + /* catch use of gnu style long options */ + if (strEQ(s, "version")) { + s = "v"; + goto reswitch; + } + if (strEQ(s, "help")) { + s = "h"; + goto reswitch; + } + s--; + /* FALL THROUGH */ default: croak("Unrecognized switch: -%s (-h will show valid options)",s); } @@ -716,7 +722,7 @@ print \" \\@INC:\\n @INC\\n\";"); switch_end: if (!tainting && (s = getenv("PERL5OPT"))) { - for (;;) { + while (s && *s) { while (isSPACE(*s)) s++; if (*s == '-') { @@ -884,7 +890,7 @@ PerlInterpreter *sv_interp; break; } - DEBUG_r(PerlIO_printf(PerlIO_stderr(), "%s $` $& $' support.\n", + DEBUG_r(PerlIO_printf(Perl_debug_log, "%s $` $& $' support.\n", sawampersand ? "Enabling" : "Omitting")); if (!restartop) { @@ -1299,30 +1305,39 @@ char *name; { /* This message really ought to be max 23 lines. * Removed -h because the user already knows that opton. Others? */ + + static char *usage[] = { +"-0[octal] specify record separator (\\0, if no argument)", +"-a autosplit mode with -n or -p (splits $_ into @F)", +"-c check syntax only (runs BEGIN and END blocks)", +"-d[:debugger] run scripts under debugger", +"-D[number/list] set debugging flags (argument is a bit mask or flags)", +"-e 'command' one line of script. Several -e's allowed. Omit [programfile].", +"-F/pattern/ split() pattern for autosplit (-a). The //'s are optional.", +"-i[extension] edit <> files in place (make backup if extension supplied)", +"-Idirectory specify @INC/#include directory (may be used more than once)", +"-l[octal] enable line ending processing, specifies line terminator", +"-[mM][-]module.. executes `use/no module...' before executing your script.", +"-n assume 'while (<>) { ... }' loop around your script", +"-p assume loop like -n but print line also like sed", +"-P run script through C preprocessor before compilation", +"-s enable some switch parsing for switches after script name", +"-S look for the script using PATH environment variable", +"-T turn on tainting checks", +"-u dump core after parsing script", +"-U allow unsafe operations", +"-v print version number and patchlevel of perl", +"-V[:variable] print perl configuration information", +"-w TURN WARNINGS ON FOR COMPILATION OF YOUR SCRIPT. Recommended.", +"-x[directory] strip off text before #!perl line and perhaps cd to directory", +"\n", +NULL +}; + char **p = usage; + printf("\nUsage: %s [switches] [--] [programfile] [arguments]", name); - printf("\n -0[octal] specify record separator (\\0, if no argument)"); - printf("\n -a autosplit mode with -n or -p (splits $_ into @F)"); - printf("\n -c check syntax only (runs BEGIN and END blocks)"); - printf("\n -d[:debugger] run scripts under debugger"); - printf("\n -D[number/list] set debugging flags (argument is a bit mask or flags)"); - printf("\n -e 'command' one line of script. Several -e's allowed. Omit [programfile]."); - printf("\n -F/pattern/ split() pattern for autosplit (-a). The //'s are optional."); - printf("\n -i[extension] edit <> files in place (make backup if extension supplied)"); - printf("\n -Idirectory specify @INC/#include directory (may be used more than once)"); - printf("\n -l[octal] enable line ending processing, specifies line terminator"); - printf("\n -[mM][-]module.. executes `use/no module...' before executing your script."); - printf("\n -n assume 'while (<>) { ... }' loop around your script"); - printf("\n -p assume loop like -n but print line also like sed"); - printf("\n -P run script through C preprocessor before compilation"); - printf("\n -s enable some switch parsing for switches after script name"); - printf("\n -S look for the script using PATH environment variable"); - printf("\n -T turn on tainting checks"); - printf("\n -u dump core after parsing script"); - printf("\n -U allow unsafe operations"); - printf("\n -v print version number and patchlevel of perl"); - printf("\n -V[:variable] print perl configuration information"); - printf("\n -w TURN WARNINGS ON FOR COMPILATION OF YOUR SCRIPT. Recommended."); - printf("\n -x[directory] strip off text before #!perl line and perhaps cd to directory\n"); + while (*p) + printf("\n %s", *p++); } /* This routine handles any switches that can be given during run */ @@ -1402,22 +1417,25 @@ char *s; inplace = savepv(s+1); /*SUPPRESS 530*/ for (s = inplace; *s && !isSPACE(*s); s++) ; - *s = '\0'; - break; - case 'I': + if (*s) + *s++ = '\0'; + return s; + case 'I': /* -I handled both here and in parse_perl() */ forbid_setid("-I"); - if (*++s) { + ++s; + while (*s && isSPACE(*s)) + ++s; + if (*s) { char *e, *p; for (e = s; *e && !isSPACE(*e); e++) ; p = savepvn(s, e-s); incpush(p, TRUE); Safefree(p); - if (*e) - return e; + s = e; } else croak("No space allowed after -I"); - break; + return s; case 'l': minus_l = TRUE; s++; @@ -1502,14 +1520,21 @@ char *s; return s; case 'v': #if defined(SUBVERSION) && SUBVERSION > 0 - printf("\nThis is perl, version 5.%03d_%02d", PATCHLEVEL, SUBVERSION); + printf("\nThis is perl, version 5.%03d_%02d built for %s", + PATCHLEVEL, SUBVERSION, ARCHNAME); #else - printf("\nThis is perl, version %s",patchlevel); + printf("\nThis is perl, version %s built for %s", + patchlevel, ARCHNAME); +#endif +#if defined(LOCAL_PATCH_COUNT) + if (LOCAL_PATCH_COUNT > 0) + printf("\n(with %d registered patch%s, see perl -V for more detail)", + LOCAL_PATCH_COUNT, (LOCAL_PATCH_COUNT!=1) ? "es" : ""); #endif printf("\n\nCopyright 1987-1997, Larry Wall\n"); #ifdef MSDOS - printf("\n\nMS-DOS port Copyright (c) 1989, 1990, Diomidis Spinellis\n"); + printf("\nMS-DOS port Copyright (c) 1989, 1990, Diomidis Spinellis\n"); #endif #ifdef DJGPP printf("djgpp v2 port (jpl5003c) by Hirofumi Watanabe, 1996\n"); diff --git a/perl.h b/perl.h index e33122a..fefceed 100644 --- a/perl.h +++ b/perl.h @@ -1578,6 +1578,8 @@ EXTCONST char* block_type[]; #include "perly.h" +#define LEX_NOTPARSING 11 /* borrowed from toke.c */ + typedef enum { XOPERATOR, XTERM, @@ -1930,7 +1932,8 @@ EXT MGVTBL vtbl_sv = {magic_get, magic_set, magic_len, 0, 0}; -EXT MGVTBL vtbl_env = {0, 0, 0, magic_clear_all_env, +EXT MGVTBL vtbl_env = {0, magic_set_all_env, + 0, magic_clear_all_env, 0}; EXT MGVTBL vtbl_envelem = {0, magic_setenv, 0, magic_clearenv, @@ -1949,7 +1952,8 @@ EXT MGVTBL vtbl_packelem = {magic_getpack, EXT MGVTBL vtbl_dbline = {0, magic_setdbline, 0, 0, 0}; EXT MGVTBL vtbl_isa = {0, magic_setisa, - 0, 0, 0}; + 0, magic_setisa, + 0}; EXT MGVTBL vtbl_isaelem = {0, magic_setisa, 0, 0, 0}; EXT MGVTBL vtbl_arylen = {magic_getarylen, diff --git a/perly.c b/perly.c index 6bc37ff..ae6a0da 100644 --- a/perly.c +++ b/perly.c @@ -1643,7 +1643,7 @@ case 27: yyval.opval = block_end(yyvsp[-4].ival, newSTATEOP(0, yyvsp[-7].pval, newWHILEOP(0, 1, (LOOP*)Nullop, - yyvsp[-3].opval, yyvsp[-1].opval, yyvsp[0].opval))); } + yyvsp[-6].ival, yyvsp[-3].opval, yyvsp[-1].opval, yyvsp[0].opval))); } break; case 28: #line 192 "perly.y" @@ -1651,7 +1651,7 @@ case 28: yyval.opval = block_end(yyvsp[-4].ival, newSTATEOP(0, yyvsp[-7].pval, newWHILEOP(0, 1, (LOOP*)Nullop, - yyvsp[-3].opval, yyvsp[-1].opval, yyvsp[0].opval))); } + yyvsp[-6].ival, yyvsp[-3].opval, yyvsp[-1].opval, yyvsp[0].opval))); } break; case 29: #line 198 "perly.y" @@ -1671,19 +1671,19 @@ case 31: break; case 32: #line 209 "perly.y" -{ copline = yyvsp[-9].ival; - yyval.opval = block_end(yyvsp[-7].ival, - newSTATEOP(0, yyvsp[-10].pval, - append_elem(OP_LINESEQ, scalar(yyvsp[-6].opval), - newWHILEOP(0, 1, (LOOP*)Nullop, - scalar(yyvsp[-4].opval), - yyvsp[0].opval, scalar(yyvsp[-2].opval))))); } +{ OP *forop = append_elem(OP_LINESEQ, + scalar(yyvsp[-6].opval), + newWHILEOP(0, 1, (LOOP*)Nullop, + yyvsp[-9].ival, scalar(yyvsp[-4].opval), + yyvsp[0].opval, scalar(yyvsp[-2].opval))); + copline = yyvsp[-9].ival; + yyval.opval = block_end(yyvsp[-7].ival, newSTATEOP(0, yyvsp[-10].pval, forop)); } break; case 33: #line 217 "perly.y" -{ yyval.opval = newSTATEOP(0, - yyvsp[-2].pval, newWHILEOP(0, 1, (LOOP*)Nullop, - Nullop, yyvsp[-1].opval, yyvsp[0].opval)); } +{ yyval.opval = newSTATEOP(0, yyvsp[-2].pval, + newWHILEOP(0, 1, (LOOP*)Nullop, + NOLINE, Nullop, yyvsp[-1].opval, yyvsp[0].opval)); } break; case 34: #line 223 "perly.y" diff --git a/perly.fixer b/perly.fixer index 98296a7..1568816 100755 --- a/perly.fixer +++ b/perly.fixer @@ -5,8 +5,9 @@ # # However, if the user wishes to use byacc, or wishes to try another # compiler compiler (e.g. bison or yacc), this script will get run. +# See makefile run_byacc target for more details. # -# Currently, only byacc version 1.8 is supported. +# Currently, only byacc version 1.8 is fully supported. # # Hacks to make it work with Interactive's SysVr3 Version 2.2 # doughera@lafvax.lafayette.edu (Andy Dougherty) 3/23/91 @@ -44,7 +45,15 @@ fi plan="unknown" -# Below, we check for various yaccpar outputs. +echo "" +echo "Warning: the yacc you have used is not directly supported by perl." +echo "The perly.fixer script will attempt to make some changes to the generated" +echo "file. The changes may be incomplete and that might lead to problems later" +echo "(especially with complex scripts). You may need to apply the changes" +echo "embedded in perl.fixer (and/or perly.c.dif*) by hand." +echo "" + +# Below, we check for various characteristic yaccpar outputs. # Test for BSD 4.3 version. # Also tests for the SunOS 4.0.2 version @@ -73,13 +82,15 @@ if *\( *\+\+yy_ps *>= *&yys\[ *YYMAXDEPTH *\] *\)' $input >$tmp 2>/dev/null fi fi +# ------ + case "$plan" in ################################################################## # The SunOS 4.0.2 version has the comparison fixed already. # Also added are out of memory checks (makes porting the generated # code easier) For most systems, it can't hurt. -- TD "bsd43") - echo "Patching perly.c to allow dynamic yacc stack allocation" + echo "Attempting to path perly.c to allow dynamic yacc stack allocation" echo "Assuming bsd4.3 yaccpar" cat >$tmp <<'END' /YYSTYPE[ ]*yyv\[ *YYMAXDEPTH *\];/c\ @@ -128,11 +139,15 @@ short *maxyyps; /yacc stack overflow.*}/d /yacc stack overflow/,/}/d END - sed -f $tmp <$input >$output ;; + if sed -f $tmp <$input >$output + then echo "The edit seems to have been applied okay." + else echo "The edit seems to have failed!" + fi + ;; ####################################################### "isc") # Interactive Systems 2.2 version - echo "Patching perly.c to allow dynamic yacc stack allocation" + echo "Attempting to path perly.c to allow dynamic yacc stack allocation" echo "Assuming Interactive SysVr3 2.2 yaccpar" # Easier to simply put whole script here than to modify the # bsd script with sed. @@ -178,11 +193,20 @@ int *maxyyps; \ }\ \ if (yyv == NULL || yys == NULL) END - sed -f $tmp < $input > $output ;; + if sed -f $tmp < $input > $output + then echo "The edit seems to have been applied okay." + else echo "The edit seems to have failed!" + fi + ;; ###################################################### # Plan still unknown - *) sed -e 's/Received token/ *** Received token/' $input >$output; + *) + echo "Unable to patch perly.c to allow dynamic yacc stack allocation (plan=$plan)" + # just do minimal change to write $output from $input + sed -e 's/Received token/ *** Received token/' $input >$output + ;; esac +echo "" rm -rf $tmp $input diff --git a/perly.y b/perly.y index be6fe98..6313061 100644 --- a/perly.y +++ b/perly.y @@ -187,13 +187,13 @@ loop : label WHILE '(' remember mtexpr ')' mblock cont $$ = block_end($4, newSTATEOP(0, $1, newWHILEOP(0, 1, (LOOP*)Nullop, - $5, $7, $8))); } + $2, $5, $7, $8))); } | label UNTIL '(' remember miexpr ')' mblock cont { copline = $2; $$ = block_end($4, newSTATEOP(0, $1, newWHILEOP(0, 1, (LOOP*)Nullop, - $5, $7, $8))); } + $2, $5, $7, $8))); } | label FOR MY remember my_scalar '(' mexpr ')' mblock cont { $$ = block_end($4, newFOROP(0, $1, $2, $5, $7, $9, $10)); } @@ -206,17 +206,17 @@ loop : label WHILE '(' remember mtexpr ')' mblock cont newFOROP(0, $1, $2, Nullop, $5, $7, $8)); } | label FOR '(' remember mnexpr ';' mtexpr ';' mnexpr ')' mblock /* basically fake up an initialize-while lineseq */ - { copline = $2; - $$ = block_end($4, - newSTATEOP(0, $1, - append_elem(OP_LINESEQ, scalar($5), - newWHILEOP(0, 1, (LOOP*)Nullop, - scalar($7), - $11, scalar($9))))); } + { OP *forop = append_elem(OP_LINESEQ, + scalar($5), + newWHILEOP(0, 1, (LOOP*)Nullop, + $2, scalar($7), + $11, scalar($9))); + copline = $2; + $$ = block_end($4, newSTATEOP(0, $1, forop)); } | label block cont /* a block is a loop that happens once */ - { $$ = newSTATEOP(0, - $1, newWHILEOP(0, 1, (LOOP*)Nullop, - Nullop, $2, $3)); } + { $$ = newSTATEOP(0, $1, + newWHILEOP(0, 1, (LOOP*)Nullop, + NOLINE, Nullop, $2, $3)); } ; nexpr : /* NULL */ diff --git a/pod/perl.pod b/pod/perl.pod index 3036f35..e989eba 100644 --- a/pod/perl.pod +++ b/pod/perl.pod @@ -242,6 +242,11 @@ See L. Larry Wall >, with the help of oodles of other folks. +If your Perl success stories and testimonials may be of help to others +who wish to advocate the use of Perl in their applications, +or if you wish to simply express your gratitude to Larry and the +Perl developers, please write to >. + =head1 FILES "/tmp/perl-e$$" temporary file for -e commands diff --git a/pod/perlapio.pod b/pod/perlapio.pod index 0db385e..c963d23 100644 --- a/pod/perlapio.pod +++ b/pod/perlapio.pod @@ -29,8 +29,8 @@ perlapio - perl's IO abstraction interface. int PerlIO_fileno(PerlIO *); PerlIO *PerlIO_fdopen(int, const char *); - PerlIO *PerlIO_importFILE(FILE *); - FILE *PerlIO_exportFILE(PerlIO *); + PerlIO *PerlIO_importFILE(FILE *, int flags); + FILE *PerlIO_exportFILE(PerlIO *, int flags); FILE *PerlIO_findFILE(PerlIO *); void PerlIO_releaseFILE(PerlIO *,FILE *); diff --git a/pod/perldelta.pod b/pod/perldelta.pod index 8d191e8..7400940 100644 --- a/pod/perldelta.pod +++ b/pod/perldelta.pod @@ -1163,7 +1163,7 @@ increasing order of desperation): =item "my" variable %s masks earlier declaration in same scope -(S) A lexical variable has been redeclared in the same scope, effectively +(W) A lexical variable has been redeclared in the same scope, effectively eliminating all access to the previous instance. This is almost always a typographical error. Note that the earlier variable will still exist until the end of the scope or until all closure referents to it are diff --git a/pod/perldiag.pod b/pod/perldiag.pod index a4d9356..166e046 100644 --- a/pod/perldiag.pod +++ b/pod/perldiag.pod @@ -35,7 +35,7 @@ if you want to localize a package variable. =item "my" variable %s masks earlier declaration in same scope -(S) A lexical variable has been redeclared in the same scope, effectively +(W) A lexical variable has been redeclared in the same scope, effectively eliminating all access to the previous instance. This is almost always a typographical error. Note that the earlier variable will still exist until the end of the scope or until all closure referents to it are @@ -594,7 +594,11 @@ for us to go to. See L. the closing delimiter was omitted. Because bracketed quotes count nesting levels, the following is missing its final parenthesis: - print q(The character '(' starts a side comment.) + print q(The character '(' starts a side comment.); + +If you're getting this error from a here-document, you may have +included unseen whitespace before or after your closing tag. A good +programmer's editor will have a way to help you find these characters. =item Can't fork @@ -778,13 +782,16 @@ of suidperl. =item Can't take log of %g -(F) Logarithms are defined on only positive real numbers. +(F) For ordinary real numbers, you can't take the logarithm of a +negative number or zero. There's a Math::Complex package that comes +standard with Perl, though, if you really want to do that for +the negative numbers. =item Can't take sqrt of %g (F) For ordinary real numbers, you can't take the square root of a -negative number. There's a Complex package available for Perl, though, -if you really want to do that. +negative number. There's a Math::Complex package that comes standard +with Perl, though, if you really want to do that. =item Can't undef active subroutine @@ -1315,10 +1322,14 @@ See L. =item Invalid type in pack: '%s' (F) The given character is not a valid pack type. See L. +(W) The given character is not a valid pack type but used to be silently +ignored. =item Invalid type in unpack: '%s' (F) The given character is not a valid unpack type. See L. +(W) The given character is not a valid unpack type but used to be silently +ignored. =item ioctl is not implemented @@ -2015,6 +2026,11 @@ an unintended loop in your inheritance hierarchy. (W) The internal sv_replace() function was handed a new SV with a reference count of other than 1. +=item regexp *+ operand could be empty + +(F) The part of the regexp subject to either the * or + quantifier +could match an empty string. + =item regexp memory corruption (P) The regular expression engine got confused by what the regular @@ -2082,6 +2098,7 @@ or setgid bit set. This doesn't make much sense. (F) The lexer couldn't find the final delimiter of a // or m{} construct. Remember that bracketing delimiters count nesting level. +Missing the leading C<$> from a variable C<$m> may cause this error. =item %sseek() on unopened file @@ -2252,11 +2269,13 @@ L. (F) The lexer couldn't find the interior delimiter of a s/// or s{}{} construct. Remember that bracketing delimiters count nesting level. +Missing the leading C<$> from variable C<$s> may cause this error. =item Substitution replacement not terminated (F) The lexer couldn't find the final delimiter of a s/// or s{}{} construct. Remember that bracketing delimiters count nesting level. +Missing the leading C<$> from variable C<$s> may cause this error. =item substr outside of string @@ -2413,7 +2432,8 @@ it. See L. =item Translation pattern not terminated (F) The lexer couldn't find the interior delimiter of a tr/// or tr[][] -construct. +or y/// or y[][] construct. Missing the leading C<$> from variables +C<$tr> or C<$y> may cause this error. =item Translation replacement not terminated @@ -2635,6 +2655,10 @@ non-methods. The simple fix for old code is: In any module that used to depend on inheriting C for non-methods from a base class named C, execute C<*AUTOLOAD = \&BaseClass::AUTOLOAD> during startup. +In code that currently says C you +should remove AutoLoader from @ISA and change C to +C. + =item Use of %s is deprecated (D) The construct indicated is no longer recommended for use, generally diff --git a/pod/perlfunc.pod b/pod/perlfunc.pod index 4f3341d..aa1e82e 100644 --- a/pod/perlfunc.pod +++ b/pod/perlfunc.pod @@ -551,23 +551,30 @@ omitted, does chroot to $_. Closes the file or pipe associated with the file handle, returning TRUE only if stdio successfully flushes buffers and closes the system file -descriptor. If the file handle came from a piped open C will -additionally return FALSE if one of the other system calls involved -fails or if the program exits with non-zero status. (If the problem was -that the program exited non-zero $! will be set to 0.) -You don't have to close FILEHANDLE if you are immediately -going to do another open() on it, because open() will close it for you. (See +descriptor. + +You don't have to close FILEHANDLE if you are immediately going to do +another open() on it, because open() will close it for you. (See open().) However, an explicit close on an input file resets the line -counter ($.), while the implicit close done by open() does not. Also, -closing a pipe will wait for the process executing on the pipe to -complete, in case you want to look at the output of the pipe -afterwards. Closing a pipe explicitly also puts the status value of -the command into C<$?>. Example: +counter ($.), while the implicit close done by open() does not. + +If the file handle came from a piped open C will additionally +return FALSE if one of the other system calls involved fails or if the +program exits with non-zero status. (If the only problem was that the +program exited non-zero $! will be set to 0.) Also, closing a pipe will +wait for the process executing on the pipe to complete, in case you +want to look at the output of the pipe afterwards. Closing a pipe +explicitly also puts the exit status value of the command into C<$?>. +Example: - open(OUTPUT, '|sort >foo'); # pipe to sort + open(OUTPUT, '|sort >foo') # pipe to sort + or die "Can't start sort: $!"; ... # print stuff to output - close OUTPUT; # wait for sort to finish - open(INPUT, 'foo'); # get sort's results + close OUTPUT # wait for sort to finish + or warn $! ? "Error closing sort pipe: $!" + : "Exit status $? from sort"; + open(INPUT, 'foo') # get sort's results + or die "Can't open 'foo' for input: $!"; FILEHANDLE may be an expression whose value gives the real filehandle name. @@ -803,11 +810,28 @@ produce, respectively See also exit() and warn(). +If LIST is empty and $@ already contains a value (typically from a +previous eval) that value is reused after appending "\t...propagated". +This is useful for propagating exceptions: + + eval { ... }; + die unless $@ =~ /Expected exception/; + +If $@ is empty then the string "Died" is used. + You can arrange for a callback to be called just before the die() does its deed, by setting the C<$SIG{__DIE__}> hook. The associated handler will be called with the error text and can change the error message, if -it sees fit, by calling die() again. See L for details on -setting C<%SIG> entries, and eval() for some examples. +it sees fit, by calling die() again. See L for details on +setting C<%SIG> entries, and L<"eval BLOCK"> for some examples. + +Note that the C<$SIG{__DIE__}> hook is called even inside eval()ed +blocks/strings. If one wants the hook to do nothing in such +situations, put + + die @_ if $^S; + +as the first line of the handler (see L). =item do BLOCK @@ -830,7 +854,7 @@ from a Perl subroutine library. is just like - eval `cat stat.pl`; + scalar eval `cat stat.pl`; except that it's more efficient, more concise, keeps track of the current filename for error messages, and searches all the B<-I> @@ -1030,10 +1054,10 @@ in case 6. =item exec LIST -The exec() function executes a system command I, -unless the command does not exist and is executed directly instead of -via your system's command shell (see below). Use system() instead of -exec() if you want it to return. +The exec() function executes a system command I - +use system() instead of exec() if you want it to return. It fails and +returns FALSE only if the command does not exist I it is executed +directly instead of via your system's command shell (see below). If there is more than one argument in LIST, or if LIST is an array with more than one value, calls execvp(3) with the arguments in LIST. If @@ -1532,8 +1556,10 @@ supported, it can cause bizarre results if the LIST is not a named array. Similarly, grep returns aliases into the original list, much like the way that L's index variable aliases the list elements. That is, modifying an element of a list returned by grep +(for example, in a C, C or another C) actually modifies the element in the original list. +See also L for an array composed of the results of the BLOCK or EXPR. =item hex EXPR =item hex @@ -1764,6 +1790,8 @@ In a scalar context, returns the ctime(3) value: $now_string = localtime; # e.g., "Thu Oct 13 04:54:34 1994" +This scalar value is B locale dependent, see L, +but instead a Perl builtin. Also see the Time::Local module, and the strftime(3) and mktime(3) function available via the POSIX module. @@ -1812,6 +1840,12 @@ is just a funny way to write $hash{getkey($_)} = $_; } +Note that, because $_ is a reference into the list value, it can be used +to modify the elements of the array. While this is useful and +supported, it can cause bizarre results if the LIST is not a named +array. See also L for an array composed of those items of the +original list for which the BLOCK or EXPR evaluates to true. + =item mkdir FILENAME,MODE Creates the directory specified by FILENAME, with permissions specified @@ -1932,6 +1966,14 @@ and those that don't is their text file formats. Systems like Unix and Plan9 that delimit lines with a single character, and that encode that character in C as '\n', do not need C. The rest need it. +When opening a file, it's usually a bad idea to continue normal execution +if the request failed, so C is frequently used in connection with +C. Even if C won't do what you want (say, in a CGI script, +where you want to make a nicely formatted error message (but there are +modules which can help with that problem)) you should always check +the return value from opening a file. The infrequent exception is when +working with an unopened filehandle is actually what you want to do. + Examples: $ARTICLE = 100; @@ -1939,12 +1981,16 @@ Examples: while (
) {... open(LOG, '>>/usr/spool/news/twitlog'); # (log is reserved) + # if the open fails, output is discarded - open(DBASE, '+/tmp/Tmp$$"); # $$ is our process id + open(EXTRACT, "|sort >/tmp/Tmp$$") # $$ is our process id + or die "Can't start sort: $!"; # process argument list of files along with any includes @@ -3060,12 +3106,13 @@ value.) The use of implicit split to @_ is deprecated, however. If EXPR is omitted, splits the $_ string. If PATTERN is also omitted, splits on whitespace (after skipping any leading whitespace). Anything matching PATTERN is taken to be a delimiter separating the fields. (Note -that the delimiter may be longer than one character.) If LIMIT is -specified and is not negative, splits into no more than that many fields -(though it may split into fewer). If LIMIT is unspecified, trailing null -fields are stripped (which potential users of pop() would do well to -remember). If LIMIT is negative, it is treated as if an arbitrarily large -LIMIT had been specified. +that the delimiter may be longer than one character.) + +If LIMIT is specified and is not negative, splits into no more than +that many fields (though it may split into fewer). If LIMIT is +unspecified, trailing null fields are stripped (which potential users +of pop() would do well to remember). If LIMIT is negative, it is +treated as if an arbitrarily large LIMIT had been specified. A pattern matching the null string (not to be confused with a null pattern C, which is just one member of the set of patterns @@ -3099,7 +3146,7 @@ If you had the entire header of a normal Unix email message in $header, you could split it up into fields and their values this way: $header =~ s/\n\s+/ /g; # fix continuation lines - %hdrs = (UNIX_FROM => split /^(.*?):\s*/m, $header); + %hdrs = (UNIX_FROM => split /^(\S*?):\s*/m, $header); The pattern C may be replaced with an expression to specify patterns that vary at runtime. (To do runtime compilation only once, @@ -3412,6 +3459,17 @@ like numbers. Note that Perl supports passing of up to only 14 arguments to your system call, which in practice should usually suffice. +Syscall returns whatever value returned by the system call it calls. +If the system call fails, syscall returns -1 and sets C<$!> (errno). +Note that some system calls can legitimately return -1. The proper +way to handle such calls is to assign C<$!=0;> before the call and +check the value of <$!> if syscall returns -1. + +There's a problem with C: it returns the file +number of the read end of the pipe it creates. There is no way +to retrieve the file number of the other end. You can avoid this +problem by using C instead. + =item sysopen FILEHANDLE,FILENAME,MODE =item sysopen FILEHANDLE,FILENAME,MODE,PERMS @@ -3441,12 +3499,12 @@ into that kind of thing. =item sysread FILEHANDLE,SCALAR,LENGTH Attempts to read LENGTH bytes of data into variable SCALAR from the -specified FILEHANDLE, using the system call read(2). It bypasses stdio, -so mixing this with other kinds of reads, print(), write(), seek(), or -tell() can cause confusion. Returns the number of bytes actually read, -or undef if there was an error. SCALAR will be grown or shrunk so that -the last byte actually read is the last byte of the scalar after the -read. +specified FILEHANDLE, using the system call read(2). It bypasses +stdio, so mixing this with other kinds of reads, print(), write(), +seek(), or tell() can cause confusion because stdio usually buffers +data. Returns the number of bytes actually read, or undef if there +was an error. SCALAR will be grown or shrunk so that the last byte +actually read is the last byte of the scalar after the read. An OFFSET may be specified to place the read data at some place in the string other than the beginning. A negative OFFSET specifies @@ -3527,14 +3585,16 @@ for details. Attempts to write LENGTH bytes of data from variable SCALAR to the specified FILEHANDLE, using the system call write(2). It bypasses stdio, so mixing this with reads (other than sysread()), print(), -write(), seek(), or tell() may cause confusion. Returns the number of -bytes actually written, or undef if there was an error. If the length -is greater than the available data, only as much data as is available +write(), seek(), or tell() may cause confusion because stdio usually +buffers data. Returns the number of bytes actually written, or undef +if there was an error. If the LENGTH is greater than the available +data in the SCALAR after the OFFSET, only as much data as is available will be written. An OFFSET may be specified to write the data from some part of the string other than the beginning. A negative OFFSET specifies writing -that many bytes counting backwards from the end of the string. +that many bytes counting backwards from the end of the string. In the +case the SCALAR is empty you can use OFFSET but only zero offset. =item tell FILEHANDLE diff --git a/pod/perlguts.pod b/pod/perlguts.pod index ecf8610..20a11ac 100644 --- a/pod/perlguts.pod +++ b/pod/perlguts.pod @@ -1404,7 +1404,7 @@ extensions. =item AvFILL -See C. +Same as C. =item av_clear @@ -1851,6 +1851,11 @@ Prepares a starting point to traverse a hash table. I32 hv_iterinit _((HV* tb)); +Note that hv_iterinit I returns the number of I in +the hash and I the number of keys (as indicated in the Advanced +Perl Programming book). This may change in future. Use the HvKEYS(hv) +macro to find the number of keys in a hash. + =item hv_iterkey Returns the key from the current position of the hash iterator. See @@ -2823,6 +2828,35 @@ Dereferences an RV to return the SV. SV* SvRV (SV* sv); +=item SvTAINT + +Taints an SV if tainting is enabled + + SvTAINT (SV* sv); + +=item SvTAINTED + +Checks to see if an SV is tainted. Returns TRUE if it is, FALSE if not. + + SvTAINTED (SV* sv); + +=item SvTAINTED_off + +Untaints an SV. Be I careful with this routine, as it short-circuits +some of Perl's fundamental security features. XS module authors should +not use this function unless they fully understand all the implications +of unconditionally untainting the value. Untainting should be done in +the standard perl fashion, via a carefully crafted regexp, rather than +directly untainting variables. + + SvTAINTED_off (SV* sv); + +=item SvTAINTED_on + +Marks an SV as tainted. + + SvTAINTED_on (SV* sv); + =item sv_setiv Copies an integer into the given SV. diff --git a/pod/perlipc.pod b/pod/perlipc.pod index 6b1f2ab..030463c 100644 --- a/pod/perlipc.pod +++ b/pod/perlipc.pod @@ -71,9 +71,9 @@ values are "inherited" by functions called from within that block.) } Sending a signal to a negative process ID means that you send the signal -to the entire Unix process-group. This code send a hang-up signal to all -processes in the current process group I the current process -itself: +to the entire Unix process-group. This code sends a hang-up signal to all +processes in the current process group (and sets $SIG{HUP} to IGNORE so +it doesn't kill itself): { local $SIG{HUP} = 'IGNORE'; diff --git a/pod/perlop.pod b/pod/perlop.pod index 5685902..17728df 100644 --- a/pod/perlop.pod +++ b/pod/perlop.pod @@ -567,6 +567,15 @@ the same character fore and aft, but the 4 sorts of brackets s{}{} Substitution yes tr{}{} Translation no +Note that there can be whitespace between the operator and the quoting +characters, except when C<#> is being used as the quoting character. +C is parsed as being the string C, which C is the +operator C followed by a comment. Its argument will be taken from the +next line. This allows you to write: + + s {foo} # Replace foo + {bar} # with bar. + For constructs that do interpolation, variables beginning with "C<$>" or "C<@>" are interpolated, as are the following sequences: @@ -619,9 +628,9 @@ patterns local to the current package are reset. This usage is vaguely deprecated, and may be removed in some future version of Perl. -=item m/PATTERN/gimosx +=item m/PATTERN/cgimosx -=item /PATTERN/gimosx +=item /PATTERN/cgimosx Searches a string for a pattern match, and in a scalar context returns true (1) or false (''). If no string is specified via the C<=~> or @@ -634,6 +643,7 @@ when C is in effect. Options are: + c Do not reset search position on a failed match when /g is in effect. g Match globally, i.e., find all occurrences. i Do case-insensitive pattern matching. m Treat string as multiple lines. diff --git a/pod/perlrun.pod b/pod/perlrun.pod index 1e3279e..a847133 100644 --- a/pod/perlrun.pod +++ b/pod/perlrun.pod @@ -62,6 +62,11 @@ getting a - instead of a complete switch could cause Perl to try to execute standard input instead of your script. And a partial B<-I> switch could also cause odd results. +Some switches do care if they are processed twice, for instance combinations +of B<-l> and B<-0>. Either put all the switches after the 32 character +boundary (if applicable), or replace the use of B<-0>I by +C. + Parsing of the #! switches starts wherever "perl" is mentioned in the line. The sequences "-*" and "- " are specifically ignored so that you could, if you were so inclined, say @@ -500,7 +505,9 @@ Perl. allows Perl to do unsafe operations. Currently the only "unsafe" operations are the unlinking of directories while running as superuser, and running setuid programs with fatal taint checks turned into -warnings. +warnings. Note that the B<-w> switch (or the C<$^W> variable) must +be used along with this option to actually B the +taint-check warnings. =item B<-v> diff --git a/pod/perlsec.pod b/pod/perlsec.pod index 1a1ae21..7388479 100644 --- a/pod/perlsec.pod +++ b/pod/perlsec.pod @@ -18,25 +18,28 @@ user or group IDs. The setuid bit in Unix permissions is mode 04000, the setgid bit mode 02000; either or both may be set. You can also enable taint mode explicitly by using the B<-T> command line flag. This flag is I suggested for server programs and any program run on behalf of -someone else, such as a CGI script. +someone else, such as a CGI script. Once taint mode is on, it's on for +the remainder of your script. While in this mode, Perl takes special precautions called I to prevent both obvious and subtle traps. Some of these checks are reasonably simple, such as verifying that path directories aren't writable by others; careful programmers have always used checks like these. Other checks, however, are best supported by the language itself, -and it is these checks especially that contribute to making a setuid Perl +and it is these checks especially that contribute to making a set-id Perl program more secure than the corresponding C program. -You may not use data derived from outside your program to affect something -else outside your program--at least, not by accident. All command line -arguments, environment variables, locale information (see L), -and file input are marked as "tainted". Tainted data may not be used -directly or indirectly in any command that invokes a sub-shell, nor in any -command that modifies files, directories, or processes. Any variable set -within an expression that has previously referenced a tainted value itself -becomes tainted, even if it is logically impossible for the tainted value -to influence the variable. Because taintedness is associated with each +You may not use data derived from outside your program to affect +something else outside your program--at least, not by accident. All +command line arguments, environment variables, locale information (see +L), results of certain system calls (readdir, readlink, +the gecos field of getpw* calls), and all file input are marked as +"tainted". Tainted data may not be used directly or indirectly in any +command that invokes a sub-shell, nor in any command that modifies +files, directories, or processes. Any variable set +to a value derived from tainted data will itself be tainted, +even if it is logically impossible for the tainted data +to alter the variable. Because taintedness is associated with each scalar value, some elements of an array can be tainted and others not. For example: @@ -90,8 +93,9 @@ doing something like the last example above. =head2 Laundering and Detecting Tainted Data To test whether a variable contains tainted data, and whose use would thus -trigger an "Insecure dependency" message, you can use the following -I function. +trigger an "Insecure dependency" message, check your nearby CPAN mirror +for the F module, which should become available around November +1997. Or you may be able to use the following I function. sub is_tainted { return ! eval { @@ -172,8 +176,8 @@ makes sure you set the PATH. It's also possible to get into trouble with other operations that don't care whether they use tainted values. Make judicious use of the file tests in dealing with any user-supplied filenames. When possible, do -opens and such after setting C<$E = $E>. (Remember group IDs, -too!) Perl doesn't prevent you from opening tainted filenames for reading, +opens and such B properly dropping any special user (or group!) +privileges. Perl doesn't prevent you from opening tainted filenames for reading, so be careful what you print out. The tainting mechanism is intended to prevent stupid mistakes, not to remove the need for thought. @@ -199,30 +203,36 @@ doing something it shouldn't. Here's a way to do backticks reasonably safely. Notice how the B is not called with a string that the shell could expand. This is by far the best way to call something that might be subjected to shell escapes: just -never call the shell at all. By the time we get to the B, tainting -is turned off, however, so be careful what you call and what you pass it. +never call the shell at all. use English; - die unless defined $pid = open(KID, "-|"); + die "Can't fork: $!" unless defined $pid = open(KID, "-|"); if ($pid) { # parent while () { # do something } close KID; } else { + my @temp = ($EUID, $EGID); $EUID = $UID; $EGID = $GID; # XXX: initgroups() not called + # Make sure privs are really gone + ($EUID, $EGID) = @temp; + die "Can't drop privileges" unless + $UID == $EUID and + $GID eq $EGID; # String test $ENV{PATH} = "/bin:/usr/bin"; - exec 'myprog', 'arg1', 'arg2'; + exec 'myprog', 'arg1', 'arg2' or die "can't exec myprog: $!"; } -A similar strategy would work for wildcard expansion via C. +A similar strategy would work for wildcard expansion via C, although +you can use C instead. Taint checking is most useful when although you trust yourself not to have written a program to give away the farm, you don't necessarily trust those who end up using it not to try to trick it into doing something bad. This -is the kind of security checking that's useful for setuid programs and +is the kind of security checking that's useful for set-id programs and programs launched on someone else's behalf, like CGI programs. This is quite different, however, from not even trusting the writer of the @@ -236,28 +246,28 @@ are trapped and namespace access is carefully controlled. =head2 Security Bugs Beyond the obvious problems that stem from giving special privileges to -systems as flexible as scripts, on many versions of Unix, setuid scripts +systems as flexible as scripts, on many versions of Unix, set-id scripts are inherently insecure right from the start. The problem is a race condition in the kernel. Between the time the kernel opens the file to -see which interpreter to run and when the (now-setuid) interpreter turns +see which interpreter to run and when the (now-set-id) interpreter turns around and reopens the file to interpret it, the file in question may have changed, especially if you have symbolic links on your system. Fortunately, sometimes this kernel "feature" can be disabled. Unfortunately, there are two ways to disable it. The system can simply -outlaw scripts with the setuid bit set, which doesn't help much. -Alternately, it can simply ignore the setuid bit on scripts. If the +outlaw scripts with any set-id bit set, which doesn't help much. +Alternately, it can simply ignore the set-id bits on scripts. If the latter is true, Perl can emulate the setuid and setgid mechanism when it notices the otherwise useless setuid/gid bits on Perl scripts. It does this via a special executable called B that is automatically invoked for you if it's needed. -However, if the kernel setuid script feature isn't disabled, Perl will -complain loudly that your setuid script is insecure. You'll need to -either disable the kernel setuid script feature, or put a C wrapper around +However, if the kernel set-id script feature isn't disabled, Perl will +complain loudly that your set-id script is insecure. You'll need to +either disable the kernel set-id script feature, or put a C wrapper around the script. A C wrapper is just a compiled program that does nothing except call your Perl program. Compiled programs are not subject to the -kernel bug that plagues setuid scripts. Here's a simple wrapper, written +kernel bug that plagues set-id scripts. Here's a simple wrapper, written in C: #define REAL_PATH "/path/to/script" @@ -278,7 +288,7 @@ for each of them. In recent years, vendors have begun to supply systems free of this inherent security bug. On such systems, when the kernel passes the name -of the setuid script to open to the interpreter, rather than using a +of the set-id script to open to the interpreter, rather than using a pathname subject to meddling, it instead passes I. This is a special file already opened on the script, so that there can be no race condition for evil scripts to exploit. On these systems, Perl should be diff --git a/pod/perlsub.pod b/pod/perlsub.pod index d08426a..16babd2 100644 --- a/pod/perlsub.pod +++ b/pod/perlsub.pod @@ -872,6 +872,12 @@ via the import syntax, and these names may then override the builtin ones: chdir $somewhere; sub chdir { ... } +To unambiguously refer to the builtin form, one may precede the +builtin name with the special package qualifier C. For example, +saying C will always refer to the builtin C, even +if the current package has imported some other subroutine called +C<&open()> from elsewhere. + Library modules should not in general export builtin names like "open" or "chdir" as part of their default @EXPORT list, because these may sneak into someone else's namespace and change the semantics unexpectedly. @@ -887,6 +893,10 @@ and it would import the open override, but if they said they would get the default imports without the overrides. +Note that such overriding is restricted to the package that requests +the import. Some means of "globally" overriding builtins may become +available in future. + =head2 Autoloading If you call a subroutine that is undefined, you would ordinarily get an diff --git a/pod/perltrap.pod b/pod/perltrap.pod index 9382789..02abc3b 100644 --- a/pod/perltrap.pod +++ b/pod/perltrap.pod @@ -35,7 +35,7 @@ Curly brackets are required on Cs and Cs. =item * -Variables begin with "$" or "@" in Perl. +Variables begin with "$", "@" or "%" in Perl. =item * @@ -168,7 +168,7 @@ There's no switch statement. (But it's easy to build one on the fly.) =item * -Variables begin with "$" or "@" in Perl. +Variables begin with "$", "@" or "%" in Perl. =item * @@ -1451,9 +1451,7 @@ Everything else. =over 5 -=item * Unclassified - -C/C trap using returned value +=item * C/C trap using returned value If the file doit.pl has: @@ -1474,6 +1472,14 @@ Running doit.pl gives the following: Same behavior if you replace C with C. +=item * C on empty string with LIMIT specified + + $string = ''; + @list = split(/foo/, $string, 2) + +Perl4 returns a one element list containing the empty string but Perl5 +returns an empty list. + =back As always, if any of these are ever officially declared as bugs, diff --git a/pod/perlvar.pod b/pod/perlvar.pod index 6487fdd..75f4e6d 100644 --- a/pod/perlvar.pod +++ b/pod/perlvar.pod @@ -18,9 +18,9 @@ long names in the current package. Some of them even have medium names, generally borrowed from B. To go a step further, those variables that depend on the currently -selected filehandle may instead be set by calling an object method on -the FileHandle object. (Summary lines below for this contain the word -HANDLE.) First you must say +selected filehandle may instead (and preferably) be set by calling an +object method on the FileHandle object. (Summary lines below for this +contain the word HANDLE.) First you must say use FileHandle; @@ -42,6 +42,12 @@ A few of these variables are considered "read-only". This means that if you try to assign to this variable, either directly or indirectly through a reference, you'll raise a run-time exception. +The following list is ordered by scalar variables first, then the +arrays, then the hashes (except $^M was added in the wrong place). +This is somewhat obscured by the fact that %ENV and %SIG are listed as +$ENV{expr} and $SIG{expr}. + + =over 8 =item $ARG @@ -438,16 +444,13 @@ operator. (Mnemonic: What just went bang?) =item $^E More specific information about the last system error than that provided by -C<$!>, if available. (If not, it's just C<$!> again, except under OS/2.) +C<$!>, if available. (If not, it's just C<$!> again.) At the moment, this differs from C<$!> under only VMS and OS/2, where it provides the VMS status value from the last system error, and OS/2 error -code of the last call to OS/2 API which was not directed via CRT. The +code of the last call to OS/2 API either via CRT, or directly from perl. The caveats mentioned in the description of C<$!> apply here, too. (Mnemonic: Extra error explanation.) -Note that under OS/2 C<$!> and C<$^E> do not track each other, so if an -OS/2-specific call is performed, you may need to check both. - =item $EVAL_ERROR =item $@ @@ -597,8 +600,8 @@ C<$^F> at the time of the open, not the time of the exec. =item $^H -The current set of syntax checks enabled by C. See the -documentation of C for more details. +The current set of syntax checks enabled by C and other block +scoped compiler hints. See the documentation of C for more details. =item $INPLACE_EDIT @@ -607,6 +610,20 @@ documentation of C for more details. The current value of the inplace-edit extension. Use C to disable inplace editing. (Mnemonic: value of B<-i> switch.) +=item $^M + +By default, running out of memory it is not trappable. However, if +compiled for this, Perl may use the contents of C<$^M> as an emergency +pool after die()ing with this message. Suppose that your Perl were +compiled with -DPERL_EMERGENCY_SBRK and used Perl's malloc. Then + + $^M = 'a' x (1<<16); + +would allocate a 64K buffer for use when in emergency. See the F +file for information on how to enable this option. As a disincentive to +casual use of this advanced feature, there is no L long name for +this variable. + =item $OSNAME =item $^O @@ -653,6 +670,12 @@ Start with single-step on. Note that some bits may be relevent at compile-time only, some at run-time only. This is a new mechanism and the details may change. +=item $^S + +Current state of the interpreter. Undefined if parsing of the current +module/eval is not finished (may happen in $SIG{__DIE__} and +$SIG{__WARN__} handlers). True if inside an eval, othewise false. + =item $BASETIME =item $^T @@ -699,6 +722,11 @@ to get the machine-dependent library properly loaded also: use lib '/mypath/libdir/'; use SomeMod; +=item @_ + +Within a subroutine the array @_ contains the parameters passed to that +subroutine. See L. + =item %INC The hash %INC contains entries for each filename that has @@ -707,25 +735,25 @@ specified, and the value is the location of the file actually found. The C command uses this array to determine whether a given file has already been included. -=item $ENV{expr} +=item %ENV $ENV{expr} The hash %ENV contains your current environment. Setting a value in C changes the environment for child processes. -=item $SIG{expr} +=item %SIG $SIG{expr} The hash %SIG is used to set signal handlers for various signals. Example: sub handler { # 1st argument is signal name - local($sig) = @_; + my($sig) = @_; print "Caught a SIG$sig--shutting down\n"; close(LOG); exit(0); } - $SIG{'INT'} = 'handler'; - $SIG{'QUIT'} = 'handler'; + $SIG{'INT'} = \&handler; + $SIG{'QUIT'} = \&handler; ... $SIG{'INT'} = 'DEFAULT'; # restore default action $SIG{'QUIT'} = 'IGNORE'; # ignore SIGQUIT @@ -733,8 +761,8 @@ signals. Example: The %SIG array contains values for only the signals actually set within the Perl script. Here are some other examples: - $SIG{PIPE} = Plumber; # SCARY!! - $SIG{"PIPE"} = "Plumber"; # just fine, assumes main::Plumber + $SIG{"PIPE"} = Plumber; # SCARY!! + $SIG{"PIPE"} = "Plumber"; # assumes main::Plumber (not recommended) $SIG{"PIPE"} = \&Plumber; # just fine; assume current Plumber $SIG{"PIPE"} = Plumber(); # oops, what did Plumber() return?? @@ -775,21 +803,30 @@ argument. When a __DIE__ hook routine returns, the exception processing continues as it would have in the absence of the hook, unless the hook routine itself exits via a C, a loop exit, or a die(). The C<__DIE__> handler is explicitly disabled during the call, so that you -can die from a C<__DIE__> handler. Similarly for C<__WARN__>. See -L, L and L. - -=item $^M - -By default, running out of memory it is not trappable. However, if -compiled for this, Perl may use the contents of C<$^M> as an emergency -pool after die()ing with this message. Suppose that your Perl were -compiled with -DPERL_EMERGENCY_SBRK and used Perl's malloc. Then - - $^M = 'a' x (1<<16); - -would allocate a 64K buffer for use when in emergency. See the F -file for information on how to enable this option. As a disincentive to -casual use of this advanced feature, there is no L long name for -this variable. +can die from a C<__DIE__> handler. Similarly for C<__WARN__>. + +Note that the C<$SIG{__DIE__}> hook is called even inside eval()ed +blocks/strings. See L, L for how to +circumvent this. + +Note that C<__DIE__>/C<__WARN__> handlers are very special in one +respect: they may be called to report (probable) errors found by the +parser. In such a case the parser may be in inconsistent state, so +any attempt to evaluate Perl code from such a handler will probably +result in a segfault. This means that calls which result/may-result +in parsing Perl should be used with extreme causion, like this: + + require Carp if defined $^S; + Carp::confess("Something wrong") if defined &Carp::confess; + die "Something wrong, but could not load Carp to give backtrace... + To see backtrace try starting Perl with -MCarp switch"; + +Here the first line will load Carp I it is the parser who +called the handler. The second line will print backtrace and die if +Carp was available. The third line will be executed only if Carp was +not available. + +See L, L and L for +additional info. =back diff --git a/pod/perlxs.pod b/pod/perlxs.pod index 13ad669..6629af2 100644 --- a/pod/perlxs.pod +++ b/pod/perlxs.pod @@ -1102,6 +1102,37 @@ that the C unary operator C<*> is considered to be a part of the C type name. TYPEMAP Netconfig *T_PTROBJ +Here's a more complicated example: suppose that you wanted C to be blessed into the class C. One way to do +this is to use underscores (_) to separate package names, as follows: + + typedef struct netconfig * Net_Config; + +And then provide a typemap entry C that maps underscores to +double-colons (::), and declare C to be of that type: + + + TYPEMAP + Net_Config T_PTROBJ_SPECIAL + + INPUT + T_PTROBJ_SPECIAL + if (sv_derived_from($arg, \"${(my $ntt=$ntype)=~s/_/::/g;\$ntt}\")) { + IV tmp = SvIV((SV*)SvRV($arg)); + $var = ($type) tmp; + } + else + croak(\"$var is not of type ${(my $ntt=$ntype)=~s/_/::/g;\$ntt}\") + + OUTPUT + T_PTROBJ_SPECIAL + sv_setref_pv($arg, \"${(my $ntt=$ntype)=~s/_/::/g;\$ntt}\", + (void*)$var); + +The INPUT and OUTPUT sections substitute underscores for double-colons +on the fly, giving the desired effect. This example demonstrates some +of the power and versatility of the typemap facility. + =head1 EXAMPLES File C: Interface to some ONC+ RPC bind library functions. diff --git a/pp.c b/pp.c index 8a31fff..3513dda 100644 --- a/pp.c +++ b/pp.c @@ -440,6 +440,68 @@ PP(pp_bless) RETURN; } +PP(pp_gelem) +{ + GV *gv; + SV *sv; + SV *ref; + char *elem; + dSP; + + sv = POPs; + elem = SvPV(sv, na); + gv = (GV*)POPs; + ref = Nullsv; + sv = Nullsv; + switch (elem ? *elem : '\0') + { + case 'A': + if (strEQ(elem, "ARRAY")) + ref = (SV*)GvAV(gv); + break; + case 'C': + if (strEQ(elem, "CODE")) + ref = (SV*)GvCVu(gv); + break; + case 'F': + if (strEQ(elem, "FILEHANDLE")) /* XXX deprecate in 5.005 */ + ref = (SV*)GvIOp(gv); + break; + case 'G': + if (strEQ(elem, "GLOB")) + ref = (SV*)gv; + break; + case 'H': + if (strEQ(elem, "HASH")) + ref = (SV*)GvHV(gv); + break; + case 'I': + if (strEQ(elem, "IO")) + ref = (SV*)GvIOp(gv); + break; + case 'N': + if (strEQ(elem, "NAME")) + sv = newSVpv(GvNAME(gv), GvNAMELEN(gv)); + break; + case 'P': + if (strEQ(elem, "PACKAGE")) + sv = newSVpv(HvNAME(GvSTASH(gv)), 0); + break; + case 'S': + if (strEQ(elem, "SCALAR")) + ref = GvSV(gv); + break; + } + if (ref) + sv = newRV(ref); + if (sv) + sv_2mortal(sv); + else + sv = &sv_undef; + XPUSHs(sv); + RETURN; +} + /* Pattern matching */ PP(pp_study) @@ -567,11 +629,11 @@ PP(pp_defined) RETPUSHNO; switch (SvTYPE(sv)) { case SVt_PVAV: - if (AvMAX(sv) >= 0 || SvRMAGICAL(sv)) + if (AvMAX(sv) >= 0 || SvGMAGICAL(sv)) RETPUSHYES; break; case SVt_PVHV: - if (HvARRAY(sv) || SvRMAGICAL(sv)) + if (HvARRAY(sv) || SvGMAGICAL(sv)) RETPUSHYES; break; case SVt_PVCV: @@ -2324,7 +2386,7 @@ PP(pp_anonhash) SV *val = NEWSV(46, 0); if (MARK < SP) sv_setsv(val, *++MARK); - else + else if (dowarn) warn("Odd number of elements in hash list"); (void)hv_store_ent(hv,key,val,0); } @@ -2383,6 +2445,12 @@ PP(pp_splice) newlen = SP - MARK; diff = newlen - length; + if (newlen && !AvREAL(ary)) { + if (AvREIFY(ary)) + av_reify(ary); + else + assert(AvREAL(ary)); /* would leak, so croak */ + } if (diff < 0) { /* shrinking the area */ if (newlen) { @@ -2694,6 +2762,7 @@ PP(pp_unpack) register U32 culong; double cdouble; static char* bitcount = 0; + int commas = 0; if (gimme != G_ARRAY) { /* arrange to do first one only */ /*SUPPRESS 530*/ @@ -2727,6 +2796,10 @@ PP(pp_unpack) switch(datumtype) { default: croak("Invalid type in unpack: '%c'", (int)datumtype); + case ',': /* grandfather in commas but with a warning */ + if (commas++ == 0 && dowarn) + warn("Invalid type in unpack: '%c'", (int)datumtype); + break; case '%': if (len == 1 && pat[-1] != '1') len = 16; @@ -3479,6 +3552,7 @@ PP(pp_pack) char *aptr; float afloat; double adouble; + int commas = 0; items = SP - MARK; MARK++; @@ -3502,6 +3576,10 @@ PP(pp_pack) switch(datumtype) { default: croak("Invalid type in pack: '%c'", (int)datumtype); + case ',': /* grandfather in commas but with a warning */ + if (commas++ == 0 && dowarn) + warn("Invalid type in pack: '%c'", (int)datumtype); + break; case '%': DIE("%% may only be used in unpack"); case '@': @@ -4113,6 +4191,11 @@ PP(pp_split) } if (realarray) { SWITCHSTACK(ary, oldstack); + if (SvSMAGICAL(ary)) { + PUTBACK; + mg_set((SV*)ary); + SPAGAIN; + } if (gimme == G_ARRAY) { EXTEND(SP, iters); Copy(AvARRAY(ary), SP + 1, iters, SV*); diff --git a/pp_ctl.c b/pp_ctl.c index 561c9fd..516e41e 100644 --- a/pp_ctl.c +++ b/pp_ctl.c @@ -2226,6 +2226,7 @@ int gimme; CvDEPTH(compcv) = 1; SP = stack_base + POPMARK; /* pop original mark */ + op = saveop; /* The caller may need it. */ RETURNOP(eval_start); } diff --git a/pp_hot.c b/pp_hot.c index 82372d0..e1f4476 100644 --- a/pp_hot.c +++ b/pp_hot.c @@ -76,68 +76,6 @@ PP(pp_gv) RETURN; } -PP(pp_gelem) -{ - GV *gv; - SV *sv; - SV *ref; - char *elem; - dSP; - - sv = POPs; - elem = SvPV(sv, na); - gv = (GV*)POPs; - ref = Nullsv; - sv = Nullsv; - switch (elem ? *elem : '\0') - { - case 'A': - if (strEQ(elem, "ARRAY")) - ref = (SV*)GvAV(gv); - break; - case 'C': - if (strEQ(elem, "CODE")) - ref = (SV*)GvCVu(gv); - break; - case 'F': - if (strEQ(elem, "FILEHANDLE")) /* XXX deprecate in 5.005 */ - ref = (SV*)GvIOp(gv); - break; - case 'G': - if (strEQ(elem, "GLOB")) - ref = (SV*)gv; - break; - case 'H': - if (strEQ(elem, "HASH")) - ref = (SV*)GvHV(gv); - break; - case 'I': - if (strEQ(elem, "IO")) - ref = (SV*)GvIOp(gv); - break; - case 'N': - if (strEQ(elem, "NAME")) - sv = newSVpv(GvNAME(gv), GvNAMELEN(gv)); - break; - case 'P': - if (strEQ(elem, "PACKAGE")) - sv = newSVpv(HvNAME(GvSTASH(gv)), 0); - break; - case 'S': - if (strEQ(elem, "SCALAR")) - ref = GvSV(gv); - break; - } - if (ref) - sv = newRV(ref); - if (sv) - sv_2mortal(sv); - else - sv = &sv_undef; - XPUSHs(sv); - RETURN; -} - PP(pp_and) { dSP; @@ -628,7 +566,8 @@ PP(pp_aassign) *(relem++) = sv; didstore = av_store(ary,i++,sv); if (magic) { - mg_set(sv); + if (SvSMAGICAL(sv)) + mg_set(sv); if (!didstore) SvREFCNT_dec(sv); } @@ -655,13 +594,14 @@ PP(pp_aassign) *(relem++) = tmpstr; didstore = hv_store_ent(hash,sv,tmpstr,0); if (magic) { - mg_set(tmpstr); + if (SvSMAGICAL(tmpstr)) + mg_set(tmpstr); if (!didstore) SvREFCNT_dec(tmpstr); } TAINT_NOT; } - if (relem == lastrelem) + if (relem == lastrelem && dowarn) warn("Odd number of elements in hash list"); } break; @@ -1755,8 +1695,11 @@ PP(pp_entersub) if (!SvROK(sv)) { char *sym; - if (sv == &sv_yes) /* unfound import, ignore */ + if (sv == &sv_yes) { /* unfound import, ignore */ + if (hasargs) + SP = stack_base + POPMARK; RETURN; + } if (SvGMAGICAL(sv)) { mg_get(sv); sym = SvPOKp(sv) ? SvPVX(sv) : Nullch; @@ -2089,6 +2032,14 @@ PP(pp_method) char* packname; STRLEN packlen; + if (SvROK(TOPs)) { + sv = SvRV(TOPs); + if (SvTYPE(sv) == SVt_PVCV) { + SETs(sv); + RETURN; + } + } + name = SvPV(TOPs, na); sv = *(stack_base + TOPMARK + 1); diff --git a/pp_sys.c b/pp_sys.c index d0915e0..d574b2e 100644 --- a/pp_sys.c +++ b/pp_sys.c @@ -1369,7 +1369,7 @@ PP(pp_send) if (-offset > blen) DIE("Offset outside string"); offset += blen; - } else if (offset >= blen) + } else if (offset >= blen && blen > 0) DIE("Offset outside string"); } else offset = 0; @@ -2402,16 +2402,20 @@ PP(pp_fttty) dSP; int fd; GV *gv; - char *tmps; - if (op->op_flags & OPf_REF) { + char *tmps = Nullch; + + if (op->op_flags & OPf_REF) gv = cGVOP->op_gv; - tmps = ""; - } + else if (isGV(TOPs)) + gv = (GV*)POPs; + else if (SvROK(TOPs) && isGV(SvRV(TOPs))) + gv = (GV*)SvRV(POPs); else gv = gv_fetchpv(tmps = POPp, FALSE, SVt_PVIO); + if (GvIO(gv) && IoIFP(GvIOp(gv))) fd = PerlIO_fileno(IoIFP(GvIOp(gv))); - else if (isDIGIT(*tmps)) + else if (tmps && isDIGIT(*tmps)) fd = atoi(tmps); else RETPUSHUNDEF; @@ -2705,6 +2709,9 @@ PP(pp_readlink) char buf[MAXPATHLEN]; int len; +#ifndef INCOMPLETE_TAINTS + TAINT; +#endif tmps = POPp; len = readlink(tmps, buf, sizeof buf); EXTEND(SP, 1); @@ -2881,6 +2888,7 @@ PP(pp_readdir) register Direntry_t *dp; GV *gv = (GV*)POPs; register IO *io = GvIOn(gv); + SV *sv; if (!io || !IoDIRP(io)) goto nope; @@ -2889,20 +2897,28 @@ PP(pp_readdir) /*SUPPRESS 560*/ while (dp = (Direntry_t *)readdir(IoDIRP(io))) { #ifdef DIRNAMLEN - XPUSHs(sv_2mortal(newSVpv(dp->d_name, dp->d_namlen))); + sv = newSVpv(dp->d_name, dp->d_namlen); #else - XPUSHs(sv_2mortal(newSVpv(dp->d_name, 0))); + sv = newSVpv(dp->d_name, 0); +#endif +#ifndef INCOMPLETE_TAINTS + SvTAINTED_on(sv); #endif + XPUSHs(sv_2mortal(sv)); } } else { if (!(dp = (Direntry_t *)readdir(IoDIRP(io)))) goto nope; #ifdef DIRNAMLEN - XPUSHs(sv_2mortal(newSVpv(dp->d_name, dp->d_namlen))); + sv = newSVpv(dp->d_name, dp->d_namlen); #else - XPUSHs(sv_2mortal(newSVpv(dp->d_name, 0))); + sv = newSVpv(dp->d_name, 0); #endif +#ifndef INCOMPLETE_TAINTS + SvTAINTED_on(sv); +#endif + XPUSHs(sv_2mortal(sv)); } RETURN; @@ -4063,6 +4079,9 @@ PP(pp_gpwent) #endif PUSHs(sv = sv_mortalcopy(&sv_no)); sv_setpv(sv, pwent->pw_gecos); +#ifndef INCOMPLETE_TAINTS + SvTAINTED_on(sv); +#endif PUSHs(sv = sv_mortalcopy(&sv_no)); sv_setpv(sv, pwent->pw_dir); PUSHs(sv = sv_mortalcopy(&sv_no)); diff --git a/proto.h b/proto.h index 84b8f06..463b498 100644 --- a/proto.h +++ b/proto.h @@ -23,6 +23,7 @@ I32 av_len _((AV* ar)); AV* av_make _((I32 size, SV** svp)); SV* av_pop _((AV* ar)); void av_push _((AV* ar, SV* val)); +void av_reify _((AV* ar)); SV* av_shift _((AV* ar)); SV** av_store _((AV* ar, I32 key, SV* val)); void av_undef _((AV* ar)); @@ -223,6 +224,7 @@ int magic_setsubstr _((SV* sv, MAGIC* mg)); int magic_settaint _((SV* sv, MAGIC* mg)); int magic_setuvar _((SV* sv, MAGIC* mg)); int magic_setvec _((SV* sv, MAGIC* mg)); +int magic_set_all_env _((SV* sv, MAGIC* mg)); int magic_wipepack _((SV* sv, MAGIC* mg)); void magicname _((char* sym, char* name, I32 namlen)); int main _((int argc, char** argv, char** env)); @@ -316,7 +318,8 @@ SV* newSVpvf _((const char* pat, ...)); SV* newSVrv _((SV* rv, char* classname)); SV* newSVsv _((SV* old)); OP* newUNOP _((I32 type, I32 flags, OP* first)); -OP* newWHILEOP _((I32 flags, I32 debuggable, LOOP* loop, OP* expr, OP* block, OP* cont)); +OP* newWHILEOP _((I32 flags, I32 debuggable, LOOP* loop, + I32 whileline, OP* expr, OP* block, OP* cont)); PerlIO* nextargv _((GV* gv)); char* ninstr _((char* big, char* bigend, char* little, char* lend)); OP* oopsCV _((OP* o)); diff --git a/regcomp.c b/regcomp.c index 3e30253..d99d6c7 100644 --- a/regcomp.c +++ b/regcomp.c @@ -257,8 +257,8 @@ PMOP* pm; if (sawplus && (!sawopen || !regsawback)) r->reganch |= ROPT_SKIP; /* x+ must match 1st of run */ - DEBUG_r(PerlIO_printf(Perl_debug_log, "first %d next %d offset %d\n", - OP(first), OP(NEXTOPER(first)), first - scan)); + DEBUG_r(PerlIO_printf(Perl_debug_log, "first %d next %d offset %ld\n", + OP(first), OP(NEXTOPER(first)), (long)(first - scan))); /* * If there's something expensive in the r.e., find the * longest literal string that must appear and make it the @@ -702,7 +702,7 @@ I32 *flagp; } if (!(flags&HASWIDTH) && op != '?') - FAIL("regexp *+ operand could be empty"); + FAIL("regexp *+ operand could be empty"); /* else may core dump */ nextchar(); @@ -1539,13 +1539,13 @@ regexp *r; op = OP(s); /* where, what */ regprop(sv, s); - PerlIO_printf(Perl_debug_log, "%2d%s", s - r->program, SvPVX(sv)); + PerlIO_printf(Perl_debug_log, "%2ld%s", (long)(s - r->program), SvPVX(sv)); next = regnext(s); s += regarglen[(U8)op]; if (next == NULL) /* Next ptr. */ PerlIO_printf(Perl_debug_log, "(0)"); else - PerlIO_printf(Perl_debug_log, "(%d)", (s-r->program)+(next-s)); + PerlIO_printf(Perl_debug_log, "(%ld)", (long)(s-r->program)+(next-s)); s += 3; if (op == ANYOF) { s += 33; diff --git a/regexec.c b/regexec.c index 271dc4d..c640d67 100644 --- a/regexec.c +++ b/regexec.c @@ -143,7 +143,8 @@ regcppop() * 0 > length [ "foobar" =~ / ( (foo) | (bar) )* /x ]->[1] */ static void -regcppartblow() +regcppartblow(base) +I32 base; { I32 i = SSPOPINT; U32 paren; @@ -160,6 +161,7 @@ regcppartblow() if (paren <= *reglastparen && regendp[paren] == endp) regstartp[paren] = startp; } + assert(savestack_ix == base); } #define regcpblow(cp) leave_scope(cp) @@ -664,8 +666,8 @@ char *prog; if (regnarrate) { SV *prop = sv_newmortal(); regprop(prop, scan); - PerlIO_printf(Perl_debug_log, "%*s%2d%-8.8s\t<%.10s>\n", - regindent*2, "", scan - regprogram, + PerlIO_printf(Perl_debug_log, "%*s%2ld%-8.8s\t<%.10s>\n", + regindent*2, "", (long)(scan - regprogram), SvPVX(prop), locinput); } #else diff --git a/scope.c b/scope.c index 98d99a4..3006f1a 100644 --- a/scope.c +++ b/scope.c @@ -165,7 +165,12 @@ save_gp(gv, empty) GV *gv; I32 empty; { - SSCHECK(3); + SSCHECK(6); + SSPUSHIV((IV)SvLEN(gv)); + SvLEN(gv) = 0; /* forget that anything was allocated here */ + SSPUSHIV((IV)SvCUR(gv)); + SSPUSHPTR(SvPVX(gv)); + SvPOK_off(gv); SSPUSHPTR(SvREFCNT_inc(gv)); SSPUSHPTR(GvGP(gv)); SSPUSHINT(SAVEt_GP); @@ -188,26 +193,50 @@ AV * save_ary(gv) GV *gv; { + AV *oav, *av; + SSCHECK(3); SSPUSHPTR(gv); - SSPUSHPTR(GvAVn(gv)); + SSPUSHPTR(oav = GvAVn(gv)); SSPUSHINT(SAVEt_AV); GvAV(gv) = Null(AV*); - return GvAVn(gv); + av = GvAVn(gv); + if (SvMAGIC(oav)) { + SvMAGIC(av) = SvMAGIC(oav); + SvFLAGS(av) |= SvMAGICAL(oav); + SvMAGICAL_off(oav); + SvMAGIC(oav) = 0; + localizing = 1; + SvSETMAGIC((SV*)av); + localizing = 0; + } + return av; } HV * save_hash(gv) GV *gv; { + HV *ohv, *hv; + SSCHECK(3); SSPUSHPTR(gv); - SSPUSHPTR(GvHVn(gv)); + SSPUSHPTR(ohv = GvHVn(gv)); SSPUSHINT(SAVEt_HV); GvHV(gv) = Null(HV*); - return GvHVn(gv); + hv = GvHVn(gv); + if (SvMAGIC(ohv)) { + SvMAGIC(hv) = SvMAGIC(ohv); + SvFLAGS(hv) |= SvMAGICAL(ohv); + SvMAGICAL_off(ohv); + SvMAGIC(ohv) = 0; + localizing = 1; + SvSETMAGIC((SV*)hv); + localizing = 0; + } + return hv; } void @@ -463,14 +492,38 @@ I32 base; case SAVEt_AV: /* array reference */ av = (AV*)SSPOPPTR; gv = (GV*)SSPOPPTR; - SvREFCNT_dec(GvAV(gv)); + if (GvAV(gv)) { + AV *goner = GvAV(gv); + SvMAGIC(av) = SvMAGIC(goner); + SvFLAGS(av) |= SvMAGICAL(goner); + SvMAGICAL_off(goner); + SvMAGIC(goner) = 0; + SvREFCNT_dec(goner); + } GvAV(gv) = av; + if (SvMAGICAL(av)) { + localizing = 2; + SvSETMAGIC((SV*)av); + localizing = 0; + } break; case SAVEt_HV: /* hash reference */ hv = (HV*)SSPOPPTR; gv = (GV*)SSPOPPTR; - SvREFCNT_dec(GvHV(gv)); + if (GvHV(gv)) { + HV *goner = GvHV(gv); + SvMAGIC(hv) = SvMAGIC(goner); + SvFLAGS(hv) |= SvMAGICAL(goner); + SvMAGICAL_off(goner); + SvMAGIC(goner) = 0; + SvREFCNT_dec(goner); + } GvHV(gv) = hv; + if (SvMAGICAL(hv)) { + localizing = 2; + SvSETMAGIC((SV*)hv); + localizing = 0; + } break; case SAVEt_INT: /* int reference */ ptr = SSPOPPTR; @@ -512,11 +565,17 @@ I32 base; gv = (GV*)SSPOPPTR; (void)sv_clear((SV*)gv); break; - case SAVEt_GP: /* scalar reference */ + case SAVEt_GP: /* scalar reference */ ptr = SSPOPPTR; gv = (GV*)SSPOPPTR; gp_free(gv); GvGP(gv) = (GP*)ptr; + if (SvPOK(gv) && SvLEN(gv) > 0) { + Safefree(SvPVX(gv)); + } + SvPVX(gv) = (char *)SSPOPPTR; + SvCUR(gv) = (STRLEN)SSPOPIV; + SvLEN(gv) = (STRLEN)SSPOPIV; SvREFCNT_dec(gv); break; case SAVEt_FREESV: @@ -615,7 +674,7 @@ void cx_dump(cx) CONTEXT* cx; { - PerlIO_printf(Perl_debug_log, "CX %d = %s\n", cx - cxstack, block_type[cx->cx_type]); + PerlIO_printf(Perl_debug_log, "CX %ld = %s\n", (long)(cx - cxstack), block_type[cx->cx_type]); if (cx->cx_type != CXt_SUBST) { PerlIO_printf(Perl_debug_log, "BLK_OLDSP = %ld\n", (long)cx->blk_oldsp); PerlIO_printf(Perl_debug_log, "BLK_OLDCOP = 0x%lx\n", (long)cx->blk_oldcop); diff --git a/sv.c b/sv.c index 6e40732..d9596cb 100644 --- a/sv.c +++ b/sv.c @@ -3005,7 +3005,7 @@ sv_collxfrm(sv, nxp) if (SvREADONLY(sv)) { SAVEFREEPV(xf); *nxp = xlen; - return xf; + return xf + sizeof(collation_ix); } if (! mg) { sv_magic(sv, 0, 'o', 0, 0); @@ -3215,8 +3215,8 @@ thats_really_all_folks: *bp = '\0'; SvCUR_set(sv, bp - (STDCHAR*)SvPVX(sv)); /* set length */ DEBUG_P(PerlIO_printf(Perl_debug_log, - "Screamer: done, len=%d, string=|%.*s|\n", - SvCUR(sv),(int)SvCUR(sv),SvPVX(sv))); + "Screamer: done, len=%ld, string=|%.*s|\n", + (long)SvCUR(sv),(int)SvCUR(sv),SvPVX(sv))); } else { @@ -4122,7 +4122,6 @@ IV iv; int sign; UV uv; char *p; - int i; sv_setpvn(sv, "", 0); if (iv >= 0) { @@ -4649,10 +4648,21 @@ sv_vcatpvfn(sv, pat, patlen, args, svargs, svmax, used_locale) sv_catpv(msg, "end of string"); warn("%_", msg); /* yes, this is reentrant */ } - /* output mangled stuff */ + + /* output mangled stuff ... */ + if (c == '\0') + --q; eptr = p; elen = q - p; - break; + + /* ... right here, because formatting flags should not apply */ + SvGROW(sv, SvCUR(sv) + elen + 1); + p = SvEND(sv); + memcpy(p, eptr, elen); + p += elen; + *p = '\0'; + SvCUR(sv) = p - SvPVX(sv); + continue; /* not "break" */ } have = esignlen + zeros + elen; diff --git a/t/TEST b/t/TEST index ae43666..cae8103 100755 --- a/t/TEST +++ b/t/TEST @@ -51,6 +51,7 @@ while ($test = shift) { chop($te); print "$te" . '.' x (18 - length($te)); if ($sharpbang) { + -x $test || (print "isn't executable.\n"); open(RESULTS,"./$test |") || (print "can't run.\n"); } else { open(SCRIPT,"$test") || die "Can't run $test.\n"; diff --git a/t/comp/proto.t b/t/comp/proto.t index 197ea78..d1cfede 100755 --- a/t/comp/proto.t +++ b/t/comp/proto.t @@ -16,7 +16,7 @@ BEGIN { use strict; -print "1..74\n"; +print "1..76\n"; my $i = 1; @@ -375,3 +375,16 @@ sub an_array_ref (\@) { an_array_ref @array; print "not " unless @array == 4; print @array; + +# correctly note too-short parameter lists that don't end with '$', +# a possible regression. + +sub foo1 ($\@); +eval q{ foo1 "s" }; +print "not " unless $@ =~ /^Not enough/; +print "ok ", $i++, "\n"; + +sub foo2 ($\%); +eval q{ foo2 "s" }; +print "not " unless $@ =~ /^Not enough/; +print "ok ", $i++, "\n"; diff --git a/t/lib/complex.t b/t/lib/complex.t index c05f40f..3390334 100755 --- a/t/lib/complex.t +++ b/t/lib/complex.t @@ -1,10 +1,15 @@ #!./perl -# $RCSfile$ +# $RCSfile: complex.t,v $ # # Regression tests for the Math::Complex pacakge -# -- Raphael Manfredi, September 1996 -# -- Jarkko Hietaniemi, March-April 1997 +# -- Raphael Manfredi September 1996 +# -- Jarkko Hietaniemi March-October 1997 +# -- Daniel S. Lewart September-October 1997 + +$VERSION = '1.05'; + +# $Id: complex.t,v 1.1 1997/10/15 10:02:15 jhi Exp jhi $ BEGIN { chdir 't' if -d 't'; @@ -13,9 +18,14 @@ BEGIN { use Math::Complex; +my ($args, $op, $target, $test, $test_set, $try, $val, $zvalue, @set, @val); + $test = 0; $| = 1; -@script = (); +my @script = ( + 'my ($res, $s0,$s1,$s2,$s3,$s4,$s5,$s6,$s7,$s8,$s9,$s10, $z0,$z1,$z2);' . + "\n\n" +); my $eps = 1e-11; while () { @@ -58,7 +68,7 @@ sub test_dbz { # push(@script, qq(print "# '$op'\n";)); push(@script, qq(eval '$op';)); push(@script, qq(print 'not ' unless (\$@ =~ /Division by zero/);)); - push(@script, qq(print "ok $test\n";)); + push(@script, qq( print "ok $test\\n";\n)); } } @@ -71,7 +81,7 @@ sub test_loz { # push(@script, qq(print "# '$op'\n";)); push(@script, qq(eval '$op';)); push(@script, qq(print 'not ' unless (\$@ =~ /Logarithm of zero/);)); - push(@script, qq(print "ok $test\n";)); + push(@script, qq( print "ok $test\\n";\n)); } } @@ -99,7 +109,10 @@ test_dbz( 'acoth(1)', ); +my $zero = cplx(0, 0); + test_loz( + 'log($zero)', 'atanh(-1)', 'acoth(-1)', ); @@ -112,7 +125,7 @@ sub test_ztz { # push(@script, qq(print "# 0**0\n";)); push(@script, qq(eval 'cplx(0)**cplx(0)';)); push(@script, qq(print 'not ' unless (\$@ =~ /zero raised to the/);)); - push(@script, qq(print "ok $test\n";)); + push(@script, qq( print "ok $test\\n";\n)); } test_ztz; @@ -126,7 +139,7 @@ sub test_broot { # push(@script, qq(print "# root(2, $op)\n";)); push(@script, qq(eval 'root(2, $op)';)); push(@script, qq(print 'not ' unless (\$@ =~ /root must be/);)); - push(@script, qq(print "ok $test\n";)); + push(@script, qq( print "ok $test\\n";\n)); } } @@ -173,11 +186,11 @@ sub test { # check the op= works push @script, <cartesian} : (\$z0, 0)); + my \$za = cplx(ref \$z0 ? \@{\$z0->cartesian} : (\$z0, 0)); my (\$z1r, \$z1i) = ref \$z1 ? \@{\$z1->cartesian} : (\$z1, 0); - my \$zb = cplx(\$z1r, \$z1i); + my \$zb = cplx(\$z1r, \$z1i); \$za $op= \$zb; my (\$zbr, \$zbi) = \@{\$zb->cartesian}; @@ -187,7 +200,7 @@ EOB $test++; # check that the rhs has not changed push @script, qq(print "not " unless (\$zbr == \$z1r and \$zbi == \$z1i);); - push @script, qq(print "ok $test\n";); + push @script, qq( print "ok $test\\n";\n); push @script, "}\n"; } } @@ -249,6 +262,17 @@ sub check { print "# '$try' expected: '$expected' got: '$got' for $args\n"; } } + +sub addsq { + my ($z1, $z2) = @_; + return ($z1 + i*$z2) * ($z1 - i*$z2); +} + +sub subsq { + my ($z1, $z2) = @_; + return ($z1 + $z2) * ($z1 - $z2); +} + __END__ &+;= (3,4):(3,4):(6,8) @@ -372,13 +396,13 @@ __END__ |'abs(z)':'r' |'acot(z)':'acotan(z)' |'acsc(z)':'acosec(z)' -|'abs(acsc(z))':'abs(asin(1 / z))' -|'abs(asec(z))':'abs(acos(1 / z))' +|'acsc(z)':'asin(1 / z)' +|'asec(z)':'acos(1 / z)' |'cbrt(z)':'cbrt(r) * exp(i * t/3)' |'cos(acos(z))':'z' -|'cos(z) ** 2 + sin(z) ** 2':1 +|'addsq(cos(z), sin(z))':1 |'cos(z)':'cosh(i*z)' -|'cosh(z) ** 2 - sinh(z) ** 2':1 +|'subsq(cosh(z), sinh(z))':1 |'cot(acot(z))':'z' |'cot(z)':'1 / tan(z)' |'cot(z)':'cotan(z)' @@ -430,6 +454,20 @@ __END__ |'atan(tan(z))':'z' |'atanh(tanh(z))':'z' +&log +(-2.0,0):( 0.69314718055995, 3.14159265358979) +(-1.0,0):( 0 , 3.14159265358979) +(-0.5,0):( -0.69314718055995, 3.14159265358979) +( 0.5,0):( -0.69314718055995, 0 ) +( 1.0,0):( 0 , 0 ) +( 2.0,0):( 0.69314718055995, 0 ) + +&log +( 2, 3):( 1.28247467873077, 0.98279372324733) +(-2, 3):( 1.28247467873077, 2.15879893034246) +(-2,-3):( 1.28247467873077, -2.15879893034246) +( 2,-3):( 1.28247467873077, -0.98279372324733) + &sin (-2.0,0):( -0.90929742682568, 0 ) (-1.0,0):( -0.84147098480790, 0 ) @@ -777,3 +815,4 @@ __END__ ( 2,-3):( 0.14694666622553, 0.23182380450040) # eof + diff --git a/t/lib/dosglob.t b/t/lib/dosglob.t new file mode 100644 index 0000000..7398a14 --- /dev/null +++ b/t/lib/dosglob.t @@ -0,0 +1,94 @@ +#!./perl + +# +# test glob() in File::DosGlob +# + +BEGIN { + chdir 't' if -d 't'; + @INC = '../lib'; +} + +print "1..9\n"; + +# override it in main:: +use File::DosGlob 'glob'; + +# test if $_ takes as the default +$_ = "lib/a*.t"; +my @r = glob; +print "not " if $_ ne 'lib/a*.t'; +print "ok 1\n"; +# we should have at least abbrev.t, anydbm.t, autoloader.t +print "# |@r|\nnot " if @r < 3; +print "ok 2\n"; + +# check if <*/*> works +@r = <*/a*.t>; +# atleast {argv,abbrev,anydbm,autoloader,append,arith,array,assignwarn,auto}.t +print "not " if @r < 9; +print "ok 3\n"; +my $r = scalar @r; + +# check if scalar context works +@r = (); +while (defined($_ = <*/a*.t>)) { + print "# $_\n"; + push @r, $_; +} +print "not " if @r != $r; +print "ok 4\n"; + +# check if array context works +@r = (); +for (<*/a*.t>) { + print "# $_\n"; + push @r, $_; +} +print "not " if @r != $r; +print "ok 5\n"; + +# test if implicit assign to $_ in while() works +@r = (); +while (<*/a*.t>) { + print "# $_\n"; + push @r, $_; +} +print "not " if @r != $r; +print "ok 6\n"; + +# test if explicit glob() gets assign magic too +my @s = (); +while (glob '*/a*.t') { + print "# $_\n"; + push @s, $_; +} +print "not " if "@r" ne "@s"; +print "ok 7\n"; + +# how about in a different package, like? +package Foo; +use File::DosGlob 'glob'; +@s = (); +while (glob '*/a*.t') { + print "# $_\n"; + push @s, $_; +} +print "not " if "@r" ne "@s"; +print "ok 8\n"; + +# test if different glob ops maintain independent contexts +@s = (); +while (<*/a*.t>) { + my $i = 0; + print "# $_ <"; + push @s, $_; + while (<*/b*.t>) { + print " $_"; + $i++; + } + print " >\n"; +} +print "not " if "@r" ne "@s"; +print "ok 9\n"; + diff --git a/t/lib/io_sock.t b/t/lib/io_sock.t index 06a973c..0971e78 100755 --- a/t/lib/io_sock.t +++ b/t/lib/io_sock.t @@ -52,6 +52,10 @@ if($pid = fork()) { } elsif(defined $pid) { + # This can fail if localhost is undefined or the + # special 'loopback' address 127.0.0.1 is not configured + # on your system. (/etc/rc.config.d/netconfig on HP-UX.) + $sock = IO::Socket::INET->new(PeerPort => $port, Proto => 'tcp', PeerAddr => 'localhost' diff --git a/t/lib/io_udp.t b/t/lib/io_udp.t index d8377f6..3e16714 100755 --- a/t/lib/io_udp.t +++ b/t/lib/io_udp.t @@ -27,6 +27,10 @@ print "1..3\n"; use Socket; use IO::Socket qw(AF_INET SOCK_DGRAM INADDR_ANY); + # This can fail if localhost is undefined or the + # special 'loopback' address 127.0.0.1 is not configured + # on your system. (/etc/rc.config.d/netconfig on HP-UX.) + $udpa = IO::Socket::INET->new(Proto => 'udp', LocalAddr => 'localhost'); $udpb = IO::Socket::INET->new(Proto => 'udp', LocalAddr => 'localhost'); diff --git a/t/op/glob.t b/t/op/glob.t index dd95e98..253e4a3 100755 --- a/t/op/glob.t +++ b/t/op/glob.t @@ -6,11 +6,12 @@ print "1..6\n"; @oops = @ops = ; -map { $files{$_}++ } ; if ($^O eq 'MSWin32') { - map { delete $files{"op/$_"} } split /[\s\n]/, `cmd /c "dir /b /l op"`; + map { $files{lc($_)}++ } ; + map { delete $files{"op/$_"} } split /[\s\n]/, `cmd /c "dir /b /l op & dir /b /l /ah op 2>nul"`, } else { + map { $files{$_}++ } ; map { delete $files{$_} } split /[\s\n]/, `echo op/*`; } if (keys %files) { diff --git a/t/op/method.t b/t/op/method.t index 21d7c8f..d955705 100755 --- a/t/op/method.t +++ b/t/op/method.t @@ -4,7 +4,7 @@ # test method calls and autoloading. # -print "1..20\n"; +print "1..24\n"; @A::ISA = 'B'; @B::ISA = 'C'; @@ -25,6 +25,14 @@ test( A->d, "C::d"); # Update hash table; test (A->d, "D::d"); # Update hash table; { + local @A::ISA = qw(C); # Update hash table with split() assignment + test (A->d, "C::d"); + $#A::ISA = -1; + test (eval { A->d } || "fail", "fail"); +} +test (A->d, "D::d"); + +{ local *B::d; eval 'sub B::d {"B::d1"}'; # Import now. test (A->d, "B::d1"); # Update hash table; @@ -109,3 +117,6 @@ test(Y->f(), "B: In Y::f, 3"); # Which sticks test(A->eee(), "new B: In A::eee, 4"); # We get a correct $autoload test(A->eee(), "new B: In A::eee, 4"); # Which sticks + +# this test added due to bug discovery +test(defined(@{"unknown_package::ISA"}) ? "defined" : "undefined", "undefined"); diff --git a/t/op/misc.t b/t/op/misc.t index 660049b..6156ac2 100755 --- a/t/op/misc.t +++ b/t/op/misc.t @@ -1,5 +1,8 @@ #!./perl +# NOTE: Please don't add tests to this file unless they *need* to be run in +# separate executable and can't simply use eval. + chdir 't' if -d 't'; @INC = "../lib"; $ENV{PERL5LIB} = "../lib"; @@ -18,8 +21,8 @@ $CAT = (($^O eq 'MSWin32') ? '.\perl -e "print <>"' : 'cat'); for (@prgs){ my $switch; - if (s/^\s*-\w+//){ - $switch = $&; + if (s/^\s*(-\w.*)//){ + $switch = $1; } my($prog,$expected) = split(/\nEXPECT\n/, $_); if ($^O eq 'MSWin32') { diff --git a/t/op/ref.t b/t/op/ref.t index e83a04f..9fcc8ac 100755 --- a/t/op/ref.t +++ b/t/op/ref.t @@ -1,6 +1,6 @@ #!./perl -print "1..50\n"; +print "1..51\n"; # Test glob operations. @@ -223,12 +223,20 @@ sub moe::DESTROY { print "# moe\nok 47\n"; } print "# left block\n"; +# another glob test + +$foo = "not ok 48"; +{ local(*bar) = "foo" } +$bar = "ok 48"; +local(*bar) = *bar; +print "$bar\n"; + package FINALE; { - $ref3 = bless ["ok 50\n"]; # package destruction - my $ref2 = bless ["ok 49\n"]; # lexical destruction - local $ref1 = bless ["ok 48\n"]; # dynamic destruction + $ref3 = bless ["ok 51\n"]; # package destruction + my $ref2 = bless ["ok 50\n"]; # lexical destruction + local $ref1 = bless ["ok 49\n"]; # dynamic destruction 1; # flush any temp values on stack } diff --git a/t/op/runlevel.t b/t/op/runlevel.t index 2be2eec..6693a82 100755 --- a/t/op/runlevel.t +++ b/t/op/runlevel.t @@ -304,7 +304,7 @@ EXPECT 0, 1, 2, 3 ######## sub foo { - goto bar if $a == 0; + goto bar if $a == 0 || $b == 0; $a <=> $b; } @a = (3, 2, 0, 1); diff --git a/t/op/split.t b/t/op/split.t index b449ba9..0724652 100755 --- a/t/op/split.t +++ b/t/op/split.t @@ -2,7 +2,7 @@ # $RCSfile: split.t,v $$Revision: 4.1 $$Date: 92/08/07 18:28:26 $ -print "1..16\n"; +print "1..20\n"; $FS = ':'; @@ -76,3 +76,17 @@ print "$a|$b" eq "2|4" ? "ok 15\n" : "not ok 15\n"; local(undef, $a, undef, $b) = qw(1 2 3 4); print "$a|$b" eq "2|4" ? "ok 16\n" : "not ok 16\n"; } + +# check splitting of null string +$_ = join('|', split(/x/, '',-1), 'Z'); +print $_ eq "Z" ? "ok 17\n" : "#$_\nnot ok 17\n"; + +$_ = join('|', split(/x/, '', 1), 'Z'); +print $_ eq "Z" ? "ok 18\n" : "#$_\nnot ok 18\n"; + +$_ = join('|', split(/(p+)/,'',-1), 'Z'); +print $_ eq "Z" ? "ok 19\n" : "#$_\nnot ok 19\n"; + +$_ = join('|', split(/.?/, '',-1), 'Z'); +print $_ eq "Z" ? "ok 20\n" : "#$_\nnot ok 20\n"; + diff --git a/t/op/sprintf.t b/t/op/sprintf.t index 8e1ef69..1450ae3 100755 --- a/t/op/sprintf.t +++ b/t/op/sprintf.t @@ -2,7 +2,32 @@ # $RCSfile: sprintf.t,v $$Revision: 4.1 $$Date: 92/08/07 18:28:27 $ -print "1..1\n"; +print "1..4\n"; +$^W = 1; +$SIG{__WARN__} = sub { + if ($_[0] =~ /^Invalid conversion/) { + $w++; + } else { + warn @_; + } +}; + +$w = 0; $x = sprintf("%3s %-4s%%foo %5d%c%3.1f","hi",123,456,65,3.0999); -if ($x eq ' hi 123 %foo 456A3.1') {print "ok 1\n";} else {print "not ok 1 '$x'\n";} +if ($x eq ' hi 123 %foo 456A3.1' && $w == 0) { + print "ok 1\n"; +} else { + print "not ok 1 '$x'\n"; +} + +for $i (2 .. 4) { + $f = ('%6 .6s', '%6. 6s', '%6.6 s')[$i - 2]; + $w = 0; + $x = sprintf($f, ''); + if ($x eq $f && $w == 1) { + print "ok $i\n"; + } else { + print "not ok $i '$x' '$f' '$w'\n"; + } +} diff --git a/t/op/subst.t b/t/op/subst.t index 3b4734e..efea970 100755 --- a/t/op/subst.t +++ b/t/op/subst.t @@ -2,7 +2,7 @@ # $RCSfile: s.t,v $$Revision: 4.1 $$Date: 92/08/07 18:28:22 $ -print "1..61\n"; +print "1..62\n"; $x = 'foo'; $_ = "x"; @@ -234,3 +234,8 @@ print exp_vars('foo $(DIR)/yyy bar',0) eq 'foo $(UNDEFINEDNAME)/xxx/yyy bar' $_ = "abcd"; s/../$x = $&, m#.#/eg; print $x eq "cd" ? "ok 61\n" : "not ok 61\n"; + +# check parsing of split subst with comment +eval 's{foo} # this is a comment, not a delimiter + {bar};'; +print @? ? "not ok 62\n" : "ok 62\n"; diff --git a/t/op/taint.t b/t/op/taint.t index e170f28..8437c43 100755 --- a/t/op/taint.t +++ b/t/op/taint.t @@ -82,7 +82,7 @@ print PROG 'print "@ARGV\n"', "\n"; close PROG; my $echo = "$Invoke_Perl $ECHO"; -print "1..135\n"; +print "1..140\n"; # First, let's make sure that Perl is checking the dangerous # environment variables. Maybe they aren't set yet, so we'll @@ -515,3 +515,60 @@ else { test 134, tainted $corge[1]; test 135, not tainted $corge[2]; } + +# Test for system/library calls returning string data of dubious origin. +{ + # No reliable %Config check for getpw* + if (eval { setpwent(); getpwent(); 1 }) { + setpwent(); + my @getpwent = getpwent(); + die "getpwent: $!\n" unless (@getpwent); + test 136,( not tainted $getpwent[0] + and not tainted $getpwent[1] + and not tainted $getpwent[2] + and not tainted $getpwent[3] + and not tainted $getpwent[4] + and not tainted $getpwent[5] + and tainted $getpwent[6] # gecos + and not tainted $getpwent[7] + and not tainted $getpwent[8]); + endpwent(); + } else { + print "# getpwent() is not available\n"; + print "ok 136\n"; + } + + if ($Config{d_readdir}) { # pretty hard to imagine not + local(*D); + opendir(D, "op") or die "opendir: $!\n"; + my $readdir = readdir(D); + test 137, tainted $readdir; + closedir(OP); + } else { + print "# readdir() is not available\n"; + print "ok 137\n"; + } + + if ($Config{d_readlink} && $Config{d_symlink}) { + my $symlink = "sl$$"; + unlink($symlink); + symlink("/something/naughty", $symlink) or die "symlink: $!\n"; + my $readlink = readlink($symlink); + test 138, tainted $readlink; + unlink($symlink); + } else { + print "# readlink() or symlink() is not available\n"; + print "ok 138\n"; + } +} + +# test bitwise ops (regression bug) +{ + my $why = "y"; + my $j = "x" | $why; + test 139, not tainted $j; + $why = $TAINT."y"; + $j = "x" | $why; + test 140, tainted $j; +} + diff --git a/t/pragma/locale.t b/t/pragma/locale.t index e1ec5a8..8e296db 100755 --- a/t/pragma/locale.t +++ b/t/pragma/locale.t @@ -394,13 +394,26 @@ for (map { chr } 0..255) { } print "ok 101\n"; +# Test for read-onlys. + +{ + no locale; + $a = "qwerty"; + { + use locale; + print "not " if $a cmp "qwerty"; + } +} +print "ok 102\n"; + +# This test must be the last one because its failure is not fatal. # The @Locale should be internally consistent. # Thanks to Hallvard Furuseth # for inventing a way to test for ordering consistency # without requiring any particular order. # ++$jhi;#@iki.fi -print "# testing 102\n"; +print "# testing 103\n"; { my ($from, $to, $lesser, $greater, @test, %test, $test, $yes, $no, $sign); @@ -422,14 +435,14 @@ print "# testing 102\n"; ( $no.' ($lesser lt $greater)', # 0 $no.' ($lesser le $greater)', # 1 - $no.' ($lesser ne $greater)', # 2 - $yes.' ($lesser eq $greater)', # 3 + 'not ($lesser ne $greater)', # 2 + ' ($lesser eq $greater)', # 3 $yes.' ($lesser ge $greater)', # 4 $yes.' ($lesser gt $greater)', # 5 $yes.' ($greater lt $lesser )', # 6 $yes.' ($greater le $lesser )', # 7 - $no.' ($greater ne $lesser )', # 8 - $yes.' ($greater eq $lesser )', # 9 + 'not ($greater ne $lesser )', # 8 + ' ($greater eq $lesser )', # 9 $no.' ($greater ge $lesser )', # 10 $no.' ($greater gt $lesser )', # 11 'not (($lesser cmp $greater) == -$sign)' # 12 @@ -438,7 +451,7 @@ print "# testing 102\n"; $test = 0; for my $ti (@test) { $test{$ti} = eval $ti ; $test ||= $test{$ti} } if ($test) { - print "# failed 102 at:\n"; + print "# failed 103 at:\n"; print "# lesser = '$lesser'\n"; print "# greater = '$greater'\n"; print "# lesser cmp greater = ", $lesser cmp $greater, "\n"; @@ -453,11 +466,10 @@ print "# testing 102\n"; print "\n"; } - print 'not '; + warn "The locale definition on your system may have errors.\n"; last; } } } -print "ok 102\n"; # eof diff --git a/taint.c b/taint.c index cd9e4ec..6776272 100644 --- a/taint.c +++ b/taint.c @@ -14,7 +14,7 @@ char *s; { char *ug; - DEBUG_u(PerlIO_printf(PerlIO_stderr(), + DEBUG_u(PerlIO_printf(Perl_debug_log, "%s %d %d %d\n", s, tainted, uid, euid)); if (tainted) { diff --git a/toke.c b/toke.c index 276ebbb..b2e8aac 100644 --- a/toke.c +++ b/toke.c @@ -66,6 +66,8 @@ static struct { * can get by with a single comparison (if the compiler is smart enough). */ +/* #define LEX_NOTPARSING 11 is done in perl.h. */ + #define LEX_NORMAL 10 #define LEX_INTERPNORMAL 9 #define LEX_INTERPCASEMOD 8 @@ -3973,7 +3975,7 @@ I32 len; case 4: if (strEQ(d,"grep")) return KEY_grep; if (strEQ(d,"goto")) return KEY_goto; - if (strEQ(d,"glob")) return -KEY_glob; + if (strEQ(d,"glob")) return KEY_glob; break; case 6: if (strEQ(d,"gmtime")) return -KEY_gmtime; @@ -4950,13 +4952,8 @@ char *start; register char *to; I32 brackets = 1; - if (isSPACE(*s)) { - /* "#" is allowed as delimiter if on same line */ - while (*s == ' ' || *s == '\t') - s++; - if (isSPACE(*s)) - s = skipspace(s); - } + if (isSPACE(*s)) + s = skipspace(s); CLINE; term = *s; multi_start = curcop->cop_line; diff --git a/unixish.h b/unixish.h index 4968a38..a13e2bd 100644 --- a/unixish.h +++ b/unixish.h @@ -106,12 +106,18 @@ #define Fflush(fp) fflush(fp) #define Mkdir(path,mode) mkdir((path),(mode)) +#ifndef PERL_SYS_INIT #ifdef PERL_SCO5 +/* this should be set in a hint file, not here */ # define PERL_SYS_INIT(c,v) fpsetmask(0) #else # define PERL_SYS_INIT(c,v) #endif +#endif + +#ifndef PERL_SYS_TERM #define PERL_SYS_TERM() +#endif #define BIT_BUCKET "/dev/null" diff --git a/util.c b/util.c index 2f222fa..819ab4e 100644 --- a/util.c +++ b/util.c @@ -188,9 +188,9 @@ MEM_SIZE size; size *= count; ptr = malloc(size?size:1); /* malloc(0) is NASTY on our system */ #if !(defined(I286) || defined(atarist)) - DEBUG_m(PerlIO_printf(PerlIO_stderr(), "0x%x: (%05d) calloc %ld x %ld bytes\n",ptr,an++,(long)count,(long)size)); + DEBUG_m(PerlIO_printf(Perl_debug_log, "0x%x: (%05d) calloc %ld x %ld bytes\n",ptr,an++,(long)count,(long)size)); #else - DEBUG_m(PerlIO_printf(PerlIO_stderr(), "0x%lx: (%05d) calloc %ld x %ld bytes\n",ptr,an++,(long)count,(long)size)); + DEBUG_m(PerlIO_printf(Perl_debug_log, "0x%lx: (%05d) calloc %ld x %ld bytes\n",ptr,an++,(long)count,(long)size)); #endif if (ptr != Nullch) { memset((void*)ptr, 0, size); @@ -691,7 +691,7 @@ perl_init_i18nl10n(printwarn) && strnNE(*e, "LC_ALL=", 7) && (p = strchr(*e, '='))) PerlIO_printf(PerlIO_stderr(), "\t%.*s = \"%s\",\n", - (p - *e), *e, p + 1); + (int)(p - *e), *e, p + 1); } } diff --git a/utils/h2ph.PL b/utils/h2ph.PL index d48571f..1b469da 100644 --- a/utils/h2ph.PL +++ b/utils/h2ph.PL @@ -50,7 +50,7 @@ die "Destination directory $Dest_dir doesn't exist or isn't a directory\n" short ushort u_short int uint u_int long ulong u_long - FILE + FILE key_t caddr_t END @isatype{@isatype} = (1) x @isatype; @@ -132,7 +132,7 @@ foreach $file (@ARGV) { print OUT $t,"eval 'sub $name () {",$new,";}' unless defined(\&$name);\n"; } else { - print OUT $t,"unless(defined(\&$name) {\nsub $name () {",$new,";}\n}\n"; + print OUT $t,"unless(defined(\&$name)) {\nsub $name () {",$new,";}\n}\n"; } } } @@ -191,9 +191,10 @@ exit $Exit; sub expr { while ($_ ne '') { + s/^\&//; # hack for things that take the address of s/^(\s+)// && do {$new .= ' '; next;}; s/^(0x[0-9a-fA-F]+)// && do {$new .= $1; next;}; - s/^(\d+)[LlUu]*// && do {$new .= $1; next;}; + s/^(\d+)\s*[LlUu]*// && do {$new .= $1; next;}; s/^("(\\"|[^"])*")// && do {$new .= $1; next;}; s/^'((\\"|[^"])*)'// && do { if ($curargs{$1}) { diff --git a/utils/h2xs.PL b/utils/h2xs.PL index 6efbde0..b736e41 100644 --- a/utils/h2xs.PL +++ b/utils/h2xs.PL @@ -418,7 +418,7 @@ END # require autoloader if XS is disabled. # if XS is enabled, require autoloader unless autoloading is disabled. -if( $opt_X && (! $opt_A) ){ +if( ($opt_X && (! $opt_A)) || (!$opt_X) ) { print PM <<"END"; require AutoLoader; END diff --git a/utils/perlbug.PL b/utils/perlbug.PL index 6b670fc..724df6b 100644 --- a/utils/perlbug.PL +++ b/utils/perlbug.PL @@ -26,18 +26,22 @@ open PATCH_LEVEL, "<../patchlevel.h" or die "Can't open patchlevel.h: $!"; my $patchlevel_date = (stat PATCH_LEVEL)[9]; while () { - last if index($_, "static\tchar\t*local_patches[] = {") >= 0; + last if $_ =~ /^\s*static\s+char.*?local_patches\[\]\s*=\s*{\s*$/; }; -my $patches; +my @patches; while () { - last if /^}/; + last if /^\s*}/; chomp; s/^\s+,?"?//; s/"?,?$//; s/(['\\])/\\$1/g; - $patches .= "'$_',\n" unless $_ eq 'NULL'; + push @patches, $_ unless $_ eq 'NULL'; }; +my $patch_desc = "'" . join("',\n\t'", @patches) . "'"; +my @patch_tags = map { my $p=$_; $p=~s/\s.*//; $p } @patches; +my $patch_tags = join " ", map { "+$_" } @patch_tags; +$patch_tags .= " " if $patch_tags; close PATCH_LEVEL; @@ -56,8 +60,13 @@ $Config{startperl} eval 'exec $Config{perlpath} -S \$0 \${1+"\$@"}' if \$running_under_some_shell; +my \$config_tag1 = '$] - $Config{cf_time}'; + my \$patchlevel_date = $patchlevel_date; -my \@patches = ( $patches ); +my \$patch_tags = '$patch_tags'; +my \@patches = ( + $patch_desc +); !GROK!THIS! # In the following, perl variables are not expanded during extraction. @@ -80,7 +89,7 @@ use strict; sub paraprint; -my($Version) = "1.19"; +my($Version) = "1.20"; # Changed in 1.06 to skip Mail::Send and Mail::Util if not available. # Changed in 1.07 to see more sendmail execs, and added pipe output. @@ -104,6 +113,7 @@ my($Version) = "1.19"; # Changed in 1.19 '-ok' default not '-v' # add local patch information # warn on '-ok' if this is an old system; add '-okay' +# Changed in 1.20 Added patchlevel.h reading and version/config checks # TODO: - Allow the user to re-name the file on mail failure, and # make sure failure (transmission-wise) of Mail::Send is @@ -114,6 +124,8 @@ my( $file, $usefile, $cc, $address, $perlbug, $testaddress, $filename, $subject, $from, $verbose, $ed, $fh, $me, $Is_MSWin32, $Is_VMS, $msg, $body, $andcc, %REP, $ok); +my $config_tag2 = "$] - $Config{cf_time}"; + Init(); if($::opt_h) { Help(); exit; } @@ -204,8 +216,8 @@ EOF $::opt_S = 1; # don't prompt for send $::opt_C = 1; # don't send a copy to the local admin $::opt_s = 1; - $subject = "OK: perl $] on" - ." $::Config{'osname'} $::Config{'osvers'} $subject"; + $subject = "OK: perl $] ${patch_tags}on" + ." $::Config{'archname'} $::Config{'osvers'} $subject"; $::opt_b = 1; $body = "Perl reported to build OK on this system.\n"; $ok = 1; @@ -292,12 +304,9 @@ EOF $domain = Mail::Util::maildomain(); } elsif ($Is_MSWin32) { $domain = $ENV{'USERDOMAIN'}; - } elsif ($Is_VMS) { + } else { require Sys::Hostname; $domain = Sys::Hostname::hostname(); - } else { - $domain = `hostname`.".".`domainname`; - $domain =~ s/[\r\n]+//g; } my($guess); @@ -534,9 +543,13 @@ EOF sub Dump { local(*OUT) = @_; - print OUT <) { - if(/^=head/) { - close(TEST); - return 1; - } + my($file, $readit) = @_; + return 1 if !$readit && $file =~ /\.pod$/i; + local($_); + open(TEST,"<$file"); + while() { + if(/^=head/) { + close(TEST); + return 1; } - close(TEST); - return 0; + } + close(TEST); + return 0; } sub minus_f_nocase { my($file) = @_; # on a case-forgiving file system we can simply use -f $file if ($Is_VMS or $Is_MSWin32 or $^O eq 'os2') { - return ( -f $file ) ? $file : ''; + return $file if -f $file and -r _; + warn "Ignored $file: unreadable\n" unless -r _; + return ''; } local *DIR; local($")="/"; my(@p,$p,$cip); foreach $p (split(/\//, $file)){ - if (-d ("@p/$p")){ + my $try = "@p/$p"; + stat $try; + if (-d _){ push @p, $p; - } elsif (-f ("@p/$p")) { - return "@p/$p"; + if ( $p eq $global_target) { + $tmp_path = join ('/', @p); + my $path_f = 0; + for (@global_found) { + $path_f = 1 if $_ eq $tmp_path; + } + push (@global_found, $tmp_path) unless $path_f; + print STDERR "Found as @p but directory\n" if $opt_v; + } + } elsif (-f _ && -r _) { + return $try; + } elsif (-f _) { + warn "Ignored $try: unreadable\n"; } else { my $found=0; my $lcp = lc $p; @@ -161,49 +189,64 @@ sub minus_f_nocase { closedir DIR; return "" unless $found; push @p, $cip; - return "@p" if -f "@p"; + return "@p" if -f "@p" and -r _; + warn "Ignored $file: unreadable\n" if -f _; } } return; # is not a file - } +} - sub searchfor { - my($recurse,$s,@dirs) = @_; - $s =~ s!::!/!g; - $s = VMS::Filespec::unixify($s) if $Is_VMS; - return $s if -f $s && containspod($s); - printf STDERR "looking for $s in @dirs\n" if $opt_v; - my $ret; - my $i; - my $dir; - for ($i=0;$i<@dirs;$i++) { - $dir = $dirs[$i]; - ($dir = VMS::Filespec::unixpath($dir)) =~ s!/$!! if $Is_VMS; - if (( $ret = minus_f_nocase "$dir/$s.pod") - or ( $ret = minus_f_nocase "$dir/$s.pm" and containspod($ret)) - or ( $ret = minus_f_nocase "$dir/$s" and containspod($ret)) - or ( $Is_VMS and - $ret = minus_f_nocase "$dir/$s.com" and containspod($ret)) + +sub check_file { + my($file) = @_; + return minus_f_nocase($file) && containspod($file) ? $file : ""; +} + + +sub searchfor { + my($recurse,$s,@dirs) = @_; + $s =~ s!::!/!g; + $s = VMS::Filespec::unixify($s) if $Is_VMS; + return $s if -f $s && containspod($s); + printf STDERR "Looking for $s in @dirs\n" if $opt_v; + my $ret; + my $i; + my $dir; + $global_target = (split('/', $s))[-1]; + for ($i=0; $i<@dirs; $i++) { + $dir = $dirs[$i]; + ($dir = VMS::Filespec::unixpath($dir)) =~ s!/$!! if $Is_VMS; + if ( ( $ret = check_file "$dir/$s.pod") + or ( $ret = check_file "$dir/$s.pm") + or ( $ret = check_file "$dir/$s") + or ( $Is_VMS and + $ret = check_file "$dir/$s.com") or ( $^O eq 'os2' and - $ret = minus_f_nocase "$dir/$s.cmd" and containspod($ret)) + $ret = check_file "$dir/$s.cmd") or ( ($Is_MSWin32 or $^O eq 'os2') and - $ret = minus_f_nocase "$dir/$s.bat" and containspod($ret)) - or ( $ret = minus_f_nocase "$dir/pod/$s.pod") - or ( $ret = minus_f_nocase "$dir/pod/$s" and containspod($ret))) - { return $ret; } - - if($recurse) { - opendir(D,$dir); - my(@newdirs) = grep(-d,map("$dir/$_",grep(!/^\.\.?$/,readdir(D)))); - closedir(D); - @newdirs = map((s/.dir$//,$_)[1],@newdirs) if $Is_VMS; - next unless @newdirs; - print STDERR "Also looking in @newdirs\n" if $opt_v; - push(@dirs,@newdirs); - } - } - return (); - } + $ret = check_file "$dir/$s.bat") + or ( $ret = check_file "$dir/pod/$s.pod") + or ( $ret = check_file "$dir/pod/$s") + ) { + return $ret; + } + + if ($recurse) { + opendir(D,$dir); + my @newdirs = map "$dir/$_", grep { + not /^\.\.?$/ and + not /^auto$/ and # save time! don't search auto dirs + -d "$dir/$_" + } readdir D; + closedir(D); + next unless @newdirs; + @newdirs = map((s/.dir$//,$_)[1],@newdirs) if $Is_VMS; + print STDERR "Also looking in @newdirs\n" if $opt_v; + push(@dirs,@newdirs); + } + } + return (); +} foreach (@pages) { @@ -230,12 +273,24 @@ foreach (@pages) { @searchdirs = grep(!/^\.$/,@INC); - @files= searchfor(1,$_,@searchdirs); if( @files ) { print STDERR "Loosely found as @files\n" if $opt_v; } else { - print STDERR "No documentation found for '$_'\n"; + print STDERR "No documentation found for \"$_\".\n"; + if (@global_found) { + print STDERR "However, try\n"; + my $dir = $file = ""; + for $dir (@global_found) { + opendir(DIR, $dir) or die "$!"; + while ($file = readdir(DIR)) { + next if ($file =~ /^\./); + $file =~ s/\.(pm|pod)$//; + print STDERR "\tperldoc $_\::$file\n"; + } + closedir DIR; + } + } } } push(@found,@files); @@ -290,13 +345,16 @@ if ($opt_f) { # Look for our function my $found = 0; + my @pod; while () { if (/^=item\s+\Q$opt_f\E\b/o) { - $found++; + $found = 1; } elsif (/^=item/) { - last if $found; + last if $found > 1; } - push(@pod, $_) if $found; + next unless $found; + push @pod, $_; + ++$found if /^\w/; # found descriptive text } if (@pod) { if ($opt_t) { diff --git a/vms/perly_c.vms b/vms/perly_c.vms index 60b0f54..ded0cf4 100644 --- a/vms/perly_c.vms +++ b/vms/perly_c.vms @@ -1646,7 +1646,7 @@ case 27: yyval.opval = block_end(yyvsp[-4].ival, newSTATEOP(0, yyvsp[-7].pval, newWHILEOP(0, 1, (LOOP*)Nullop, - yyvsp[-3].opval, yyvsp[-1].opval, yyvsp[0].opval))); } + yyvsp[-6].ival, yyvsp[-3].opval, yyvsp[-1].opval, yyvsp[0].opval))); } break; case 28: #line 192 "perly.y" @@ -1654,7 +1654,7 @@ case 28: yyval.opval = block_end(yyvsp[-4].ival, newSTATEOP(0, yyvsp[-7].pval, newWHILEOP(0, 1, (LOOP*)Nullop, - yyvsp[-3].opval, yyvsp[-1].opval, yyvsp[0].opval))); } + yyvsp[-6].ival, yyvsp[-3].opval, yyvsp[-1].opval, yyvsp[0].opval))); } break; case 29: #line 198 "perly.y" @@ -1674,19 +1674,19 @@ case 31: break; case 32: #line 209 "perly.y" -{ copline = yyvsp[-9].ival; - yyval.opval = block_end(yyvsp[-7].ival, - newSTATEOP(0, yyvsp[-10].pval, - append_elem(OP_LINESEQ, scalar(yyvsp[-6].opval), - newWHILEOP(0, 1, (LOOP*)Nullop, - scalar(yyvsp[-4].opval), - yyvsp[0].opval, scalar(yyvsp[-2].opval))))); } +{ OP *forop = append_elem(OP_LINESEQ, + scalar(yyvsp[-6].opval), + newWHILEOP(0, 1, (LOOP*)Nullop, + yyvsp[-9].ival, scalar(yyvsp[-4].opval), + yyvsp[0].opval, scalar(yyvsp[-2].opval))); + copline = yyvsp[-9].ival; + yyval.opval = block_end(yyvsp[-7].ival, newSTATEOP(0, yyvsp[-10].pval, forop)); } break; case 33: #line 217 "perly.y" -{ yyval.opval = newSTATEOP(0, - yyvsp[-2].pval, newWHILEOP(0, 1, (LOOP*)Nullop, - Nullop, yyvsp[-1].opval, yyvsp[0].opval)); } +{ yyval.opval = newSTATEOP(0, yyvsp[-2].pval, + newWHILEOP(0, 1, (LOOP*)Nullop, + NOLINE, Nullop, yyvsp[-1].opval, yyvsp[0].opval)); } break; case 34: #line 223 "perly.y" diff --git a/vms/vms.c b/vms/vms.c index 32f734b..f225790 100644 --- a/vms/vms.c +++ b/vms/vms.c @@ -3177,7 +3177,7 @@ void my_endpwent() } /*}}}*/ - +#if __VMS_VER < 70000000 || __DECC_VER < 50200000 /* Used for UTC calculation in my_gmtime(), my_localtime(), my_time(), * my_utime(), and flex_stat(), all of which operate on UTC unless * VMSISH_TIMES is true. @@ -3303,6 +3303,7 @@ my_localtime(const time_t *timep) #define localtime(t) my_localtime(t) #define time(t) my_time(t) +#endif /* VMS VER < 7.0 || Dec C < 5.2 /* my_utime - update modification time of a file * calling sequence is identical to POSIX utime(), but under @@ -3366,7 +3367,7 @@ int my_utime(char *file, struct utimbuf *utimes) */ lowbit = (utimes->modtime & 1) ? secscale : 0; unixtime = (long int) utimes->modtime; -# ifdef VMSISH_TIME +#if defined(VMSISH_TIME) && (__VMS_VER < 70000000 || __DECC_VER < 50200000) if (!VMSISH_TIME) { /* Input was UTC; convert to local for sys svc */ if (!gmtime_emulation_type) (void) time(NULL); /* Initialize UTC */ unixtime += utc_offset_secs; @@ -3716,10 +3717,12 @@ flex_fstat(int fd, struct mystat *statbufp) # else if (1) { # endif +#if __VMS_VER < 70000000 || __DECC_VER < 50200000 if (!gmtime_emulation_type) (void)time(NULL); statbufp->st_mtime -= utc_offset_secs; statbufp->st_atime -= utc_offset_secs; statbufp->st_ctime -= utc_offset_secs; +#endif } return 0; } @@ -3769,10 +3772,12 @@ flex_stat(char *fspec, struct mystat *statbufp) # else if (1) { # endif +#if __VMS_VER < 70000000 || __DECC_VER < 50200000 if (!gmtime_emulation_type) (void)time(NULL); statbufp->st_mtime -= utc_offset_secs; statbufp->st_atime -= utc_offset_secs; statbufp->st_ctime -= utc_offset_secs; +#endif } } return retval; diff --git a/vms/vmsish.h b/vms/vmsish.h index 81e3764..2da1639 100644 --- a/vms/vmsish.h +++ b/vms/vmsish.h @@ -111,9 +111,11 @@ # define seekdir Perl_seekdir # define closedir Perl_closedir # define vmsreaddirversions Perl_vmsreaddirversions +#if __VMS_VER < 70000000 || __DECC_VER < 50200000 # define my_gmtime Perl_my_gmtime # define my_localtime Perl_my_localtime # define my_time Perl_my_time +#endif # define cando_by_name Perl_cando_by_name # define flex_fstat Perl_flex_fstat # define flex_stat Perl_flex_stat @@ -330,9 +332,11 @@ struct utimbuf { * in VMS 6.0 or later use. We also add shims for time() and localtime() * so we can run on UTC by default. */ +#if __VMS_VER < 70000000 || __DECC_VER < 50200000 #define gmtime(t) my_gmtime(t) #define localtime(t) my_localtime(t) #define time(t) my_time(t) +#endif /* VMS doesn't use a real sys_nerr, but we need this when scanning for error * messages in text strings . . . @@ -532,9 +536,11 @@ long telldir _((DIR *)); void seekdir _((DIR *, long)); void closedir _((DIR *)); void vmsreaddirversions _((DIR *, int)); +#ifdef my_gmtime struct tm * my_gmtime _((const time_t *)); struct tm * my_localtime _((const time_t *)); time_t my_time _((time_t *)); +#endif /* We're assuming these three come as a package */ I32 cando_by_name _((I32, I32, char *)); int flex_fstat _((int, struct mystat *)); int flex_stat _((char *, struct mystat *)); diff --git a/win32/Makefile b/win32/Makefile index 9e4437f..7a98f84 100644 --- a/win32/Makefile +++ b/win32/Makefile @@ -201,6 +201,11 @@ WIN32_OBJ = win32.obj \ win32io.obj \ win32sck.obj +PERL95_OBJ = perl95.obj \ + win32mt.obj \ + win32iomt.obj \ + win32sckmt.obj + DLL_OBJ = perllib.obj $(DYNALOADER).obj CORE_H = ..\av.h \ @@ -356,9 +361,15 @@ perl95.obj : perl95.c win32iomt.obj : win32io.c $(CC) $(CFLAGS) -MT -c $(OBJOUT_FLAG)win32iomt.obj win32io.c -$(PERL95EXE): $(PERLDLL) $(CONFIGPM) perl95.obj win32iomt.obj +win32sckmt.obj : win32sck.c + $(CC) $(CFLAGS) -MT -c $(OBJOUT_FLAG)win32sckmt.obj win32sck.c + +win32mt.obj : win32.c + $(CC) $(CFLAGS) -MT -c $(OBJOUT_FLAG)win32mt.obj win32.c + +$(PERL95EXE): $(PERLDLL) $(CONFIGPM) $(PERL95_OBJ) $(LINK32) -subsystem:console -out:perl95.exe $(LINK_FLAGS) \ - perl95.obj win32iomt.obj $(PERLIMPLIB) + $(PERL95_OBJ) $(PERLIMPLIB) copy perl95.exe $@ del perl95.exe @@ -469,10 +480,18 @@ minitest : $(MINIPERL) $(GLOBEXE) $(CONFIGPM) $(MINIPERL) -I..\lib test base/*.t comp/*.t cmd/*.t io/*.t op/*.t pragma/*.t cd ..\win32 -test : all +test-prep : all $(XCOPY) $(PERLEXE) ..\t\$(NULL) $(XCOPY) $(PERLDLL) ..\t\$(NULL) $(XCOPY) $(GLOBEXE) ..\t\$(NULL) + +test : test-prep + cd ..\t + $(PERLEXE) -I..\lib harness + cd ..\win32 + +test-notty : test-prep + set PERL_SKIP_TTY_TEST=1 cd ..\t $(PERLEXE) -I..\lib harness cd ..\win32 diff --git a/win32/config_H.bc b/win32/config_H.bc index 1883e97..61fb5a3 100644 --- a/win32/config_H.bc +++ b/win32/config_H.bc @@ -47,7 +47,11 @@ * where library files may be held under a private library, for * instance. */ -#define ARCHNAME "MSWin32" /**/ +#ifdef _ALPHA_ +#define ARCHNAME "alpha-mswin32" /**/ +#else +#define ARCHNAME "x86-mswin32" /**/ +#endif /* BIN: * This symbol holds the path of the bin directory where the package will diff --git a/win32/config_H.vc b/win32/config_H.vc index 36a9a5b..76f19f1 100644 --- a/win32/config_H.vc +++ b/win32/config_H.vc @@ -47,7 +47,11 @@ * where library files may be held under a private library, for * instance. */ -#define ARCHNAME "MSWin32" /**/ +#ifdef _ALPHA_ +#define ARCHNAME "alpha-mswin32" /**/ +#else +#define ARCHNAME "x86-mswin32" /**/ +#endif /* BIN: * This symbol holds the path of the bin directory where the package will diff --git a/win32/makefile.mk b/win32/makefile.mk index 4696dcb..dbac98f 100644 --- a/win32/makefile.mk +++ b/win32/makefile.mk @@ -267,6 +267,11 @@ WIN32_OBJ = win32.obj \ win32io.obj \ win32sck.obj +PERL95_OBJ = perl95.obj \ + win32mt.obj \ + win32iomt.obj \ + win32sckmt.obj + DLL_OBJ = perllib.obj $(DYNALOADER).obj CORE_H = ..\av.h \ @@ -455,9 +460,15 @@ perl95.obj : perl95.c win32iomt.obj : win32io.c $(CC) $(CFLAGS) -MT -c $(OBJOUT_FLAG)win32iomt.obj win32io.c -$(PERL95EXE): $(PERLDLL) $(CONFIGPM) perl95.obj win32iomt.obj +win32sckmt.obj : win32sck.c + $(CC) $(CFLAGS) -MT -c $(OBJOUT_FLAG)win32sckmt.obj win32sck.c + +win32mt.obj : win32.c + $(CC) $(CFLAGS) -MT -c $(OBJOUT_FLAG)win32mt.obj win32.c + +$(PERL95EXE): $(PERLDLL) $(CONFIGPM) $(PERL95_OBJ) $(LINK32) -subsystem:console -out:perl95.exe $(LINK_FLAGS) \ - perl95.obj win32iomt.obj $(PERLIMPLIB) + $(PERL95_OBJ) $(PERLIMPLIB) copy perl95.exe $@ del perl95.exe diff --git a/win32/pod.mak b/win32/pod.mak index 538cfa3..9881ed8 100644 --- a/win32/pod.mak +++ b/win32/pod.mak @@ -9,7 +9,7 @@ POD2HTML = pod2html \ all: $(CONVERTERS) html PERL = ..\miniperl.exe -PL2BAT = ..\win32\bin\pl2bat.bat +PL2BAT = ..\win32\bin\pl2bat.pl POD = \ perl.pod \ diff --git a/win32/win32.c b/win32/win32.c index 7a4c285..7cbfae8 100644 --- a/win32/win32.c +++ b/win32/win32.c @@ -1564,6 +1564,7 @@ XS(w32_GetShortPathName) { dXSARGS; SV *shortpath; + DWORD len; if(items != 1) croak("usage: Win32::GetShortPathName($longPathName)"); @@ -1571,8 +1572,15 @@ XS(w32_GetShortPathName) shortpath = sv_mortalcopy(ST(0)); SvUPGRADE(shortpath, SVt_PV); /* src == target is allowed */ - if (GetShortPathName(SvPVX(shortpath), SvPVX(shortpath), SvCUR(shortpath))) + do { + len = GetShortPathName(SvPVX(shortpath), + SvPVX(shortpath), + SvLEN(shortpath)); + } while (len >= SvLEN(shortpath) && sv_grow(shortpath,len+1)); + if (len) { + SvCUR_set(shortpath,len); ST(0) = shortpath; + } else ST(0) = &sv_undef; XSRETURN(1); diff --git a/win32/win32io.c b/win32/win32io.c index 12bc645..eeb6846 100644 --- a/win32/win32io.c +++ b/win32/win32io.c @@ -238,6 +238,7 @@ my_flock(int fd, int oper) #undef LK_ERR #undef LK_LEN +EXT int my_fclose(FILE *pf); #ifdef PERLDLL __declspec(dllexport) @@ -259,7 +260,7 @@ WIN32_IOSUBSYSTEM win32stdio = { fopen, /* (*pfunc_fopen)(const char *path, const char *mode); */ fdopen, /* (*pfunc_fdopen)(int fh, const char *mode); */ freopen, /* (*pfunc_freopen)(const char *path, const char *mode, FILE *pf); */ - fclose, /* (*pfunc_fclose)(FILE *pf); */ + my_fclose, /* (*pfunc_fclose)(FILE *pf); */ fputs, /* (*pfunc_fputs)(const char *s,FILE *pf); */ fputc, /* (*pfunc_fputc)(int c,FILE *pf); */ ungetc, /* (*pfunc_ungetc)(int c,FILE *pf); */ diff --git a/win32/win32sck.c b/win32/win32sck.c index d541a7e..3653fc8 100644 --- a/win32/win32sck.c +++ b/win32/win32sck.c @@ -227,11 +227,11 @@ myfdopen(int fd, char *mode) int retval; if (hWinSockDll == 0) - LoadWinSock(); + return(fdopen(fd, mode)); retval = pgetsockopt((SOCKET)fd, SOL_SOCKET, SO_TYPE, sockbuf, &optlen); if(retval == SOCKET_ERROR && pWSAGetLastError() == WSAENOTSOCK) { - return(_fdopen(fd, mode)); + return(fdopen(fd, mode)); } /* @@ -258,7 +258,7 @@ u_long win32_htonl(u_long hostlong) { if(hWinSockDll == 0) - LoadWinSock(); + StartSockets(); return phtonl(hostlong); } @@ -267,7 +267,7 @@ u_short win32_htons(u_short hostshort) { if(hWinSockDll == 0) - LoadWinSock(); + StartSockets(); return phtons(hostshort); } @@ -276,7 +276,7 @@ u_long win32_ntohl(u_long netlong) { if(hWinSockDll == 0) - LoadWinSock(); + StartSockets(); return pntohl(netlong); } @@ -285,7 +285,7 @@ u_short win32_ntohs(u_short netshort) { if(hWinSockDll == 0) - LoadWinSock(); + StartSockets(); return pntohs(netshort); } @@ -503,6 +503,22 @@ win32_socket(int af, int type, int protocol) return s; } +#undef fclose +int +my_fclose (FILE *pf) +{ + int osf, retval; + if (hWinSockDll == 0) /* No WinSockDLL? */ + return(fclose(pf)); /* Then not a socket. */ + osf = TO_SOCKET(fileno(pf)); /* Get it now before it's gone! */ + retval = fclose(pf); /* Must fclose() before closesocket() */ + if (osf != -1 + && pclosesocket(osf) == SOCKET_ERROR + && WSAGetLastError() != WSAENOTSOCK) + retval = EOF; + return retval; +} + struct hostent * win32_gethostbyaddr(const char *addr, int len, int type) { @@ -576,7 +592,7 @@ char FAR * win32_inet_ntoa(struct in_addr in) { if(hWinSockDll == 0) - LoadWinSock(); + StartSockets(); return pinet_ntoa(in); } @@ -585,7 +601,7 @@ unsigned long win32_inet_addr(const char FAR *cp) { if(hWinSockDll == 0) - LoadWinSock(); + StartSockets(); return pinet_addr(cp); diff --git a/x2p/Makefile.SH b/x2p/Makefile.SH index 0ca3ff3..65a3d75 100755 --- a/x2p/Makefile.SH +++ b/x2p/Makefile.SH @@ -132,7 +132,7 @@ lint: lint $(lintflags) $(defs) $(c) > a2p.fuzz depend: $(mallocsrc) ../makedepend - sh ../makedepend + sh ../makedepend MAKE=$(MAKE) clist: echo $(c) | tr ' ' '\012' >.clist diff --git a/x2p/util.c b/x2p/util.c index e8b666f..469beb0 100644 --- a/x2p/util.c +++ b/x2p/util.c @@ -33,8 +33,8 @@ MEM_SIZE size; ptr = malloc(size ? size : 1); #ifdef DEBUGGING if (debug & 128) - fprintf(stderr,"0x%lx: (%05d) malloc %d bytes\n",(unsigned long)ptr, - an++,size); + fprintf(stderr,"0x%lx: (%05d) malloc %ld bytes\n",(unsigned long)ptr, + an++,(long)size); #endif if (ptr != Nullch) return ptr; @@ -59,7 +59,7 @@ MEM_SIZE size; #ifdef DEBUGGING if (debug & 128) { fprintf(stderr,"0x%lx: (%05d) rfree\n",(unsigned long)where,an++); - fprintf(stderr,"0x%lx: (%05d) realloc %d bytes\n",(unsigned long)ptr,an++,size); + fprintf(stderr,"0x%lx: (%05d) realloc %ld bytes\n",(unsigned long)ptr,an++,(long)size); } #endif if (ptr != Nullch)