diff options
author | Todd C. Miller <millert@cvs.openbsd.org> | 2002-10-27 22:25:41 +0000 |
---|---|---|
committer | Todd C. Miller <millert@cvs.openbsd.org> | 2002-10-27 22:25:41 +0000 |
commit | d85c2f57f17d991a6ca78d3e1c9f3308a2bbb271 (patch) | |
tree | 8c9a359433cbb3488b0a848e99bd869c76295dfd /gnu/usr.bin/perl/os2 | |
parent | 74cfb115ac810480c0000dc742b20383c1578bac (diff) |
Resolve conflicts, remove old files, merge local changes
Diffstat (limited to 'gnu/usr.bin/perl/os2')
-rw-r--r-- | gnu/usr.bin/perl/os2/Changes | 161 | ||||
-rw-r--r-- | gnu/usr.bin/perl/os2/Makefile.SHs | 276 | ||||
-rw-r--r-- | gnu/usr.bin/perl/os2/OS2/ExtAttr/Makefile.PL | 2 | ||||
-rw-r--r-- | gnu/usr.bin/perl/os2/OS2/PrfDB/Makefile.PL | 2 | ||||
-rw-r--r-- | gnu/usr.bin/perl/os2/OS2/PrfDB/PrfDB.xs | 48 | ||||
-rw-r--r-- | gnu/usr.bin/perl/os2/OS2/Process/Makefile.PL | 32 | ||||
-rw-r--r-- | gnu/usr.bin/perl/os2/OS2/Process/Process.pm | 1110 | ||||
-rw-r--r-- | gnu/usr.bin/perl/os2/OS2/Process/Process.xs | 837 | ||||
-rw-r--r-- | gnu/usr.bin/perl/os2/OS2/REXX/Makefile.PL | 2 | ||||
-rw-r--r-- | gnu/usr.bin/perl/os2/OS2/REXX/REXX.pm | 63 | ||||
-rw-r--r-- | gnu/usr.bin/perl/os2/OS2/REXX/REXX.xs | 239 | ||||
-rw-r--r-- | gnu/usr.bin/perl/os2/OS2/REXX/t/rx_cmprt.t | 8 | ||||
-rw-r--r-- | gnu/usr.bin/perl/os2/OS2/REXX/t/rx_vrexx.t | 6 | ||||
-rw-r--r-- | gnu/usr.bin/perl/os2/diff.configure | 32 | ||||
-rw-r--r-- | gnu/usr.bin/perl/os2/dl_os2.c | 42 | ||||
-rw-r--r-- | gnu/usr.bin/perl/os2/dlfcn.h | 4 | ||||
-rw-r--r-- | gnu/usr.bin/perl/os2/os2.c | 1114 | ||||
-rw-r--r-- | gnu/usr.bin/perl/os2/os2ish.h | 341 |
18 files changed, 3807 insertions, 512 deletions
diff --git a/gnu/usr.bin/perl/os2/Changes b/gnu/usr.bin/perl/os2/Changes index 7f639582362..4c54a28d5cb 100644 --- a/gnu/usr.bin/perl/os2/Changes +++ b/gnu/usr.bin/perl/os2/Changes @@ -334,3 +334,164 @@ pre 5.6.1: compartment. As a result, the return string was not initialized. A complete example of a mini-application added to OS2::REXX. README.os2 updated to reflect the current state of Perl. + +pre 5.7.2: + aout build: kid bootstrap_* were not associated with XS. + bldlevel did not contain enough info. + extLibpath* was failing on the call of the second type. + Configure defines flushNULL now (EMX -Zomf bug broke autodetection). + Configure did not find SIGBREAK. + extLibpath supports LIBSTRICT, better error detection. + crypt() used if present in -lcrypt or -lufc. + dumb getpw*(), getgr*() etc. supported; as in EMX, but if no + $ENV{PW_PASSWD}, the passwd field contains a string which + cannot be returned by crypt() (for security reasons). + The unwound recursion in detecting executable by script was + using static buffers. Thus system('pod2text') would fail if the + current directory contained an empty file named 'perl'. + Put ordinals in the base DLL. + Enable EXE-compression. + Load time (ms): Without /e:2: 70.6; With /e:2: 75.3; Lxlite: 62.8 + Size drops from 750K to 627K, with lxlite to 515K. + lxlite /c:max gives 488K, but dumps core in t/TEST + os2ish.h defines SYSLOG constants ==> Sys::Syslog works. + Corrected warnings related to OS/2 code. + At one place = was put instead of ==. + Setting $^E should work. + Force "SYS0dddd=0xbar: " to error messages and to dlerror(). + ($^E == 2 printed SYS0002 itself, but 110 did not.) + $OS2::nsyserror=0 switches off forcing SYSdddd on $^E. + perl_.exe does not require PM dlls any more (symbols resolved at + runtime on the as needed basis). + OS2::Process: + get/set: term size; codepages; screen's cursor; screen's contents + reliable session name setting; + process's parent pid, and the session id; + switching to and enumeration of sessions + window hierarchy inspection + post a message to a window + More robust getpriority() on older Warps. + + New C APIs for runtime loading of entry points from DLLs + (useful for entry points not present on older versions of + OS/2, or with DLLs not present on floppy-boot stripped down + setups): CallORD(), DeclFuncByORD(), DeclVoidFuncByORD(), + DeclOSFuncByORD(), DeclWinFuncByORD(), AssignFuncPByORD(). + +pre 5.7.3: + Testing with PERL_TEST_NOVREXX=1 in environment makes tests + noninteractive (VREXX test requires pressing a button on a dialog). + + New (ugly and voodooish) hack to work around a bug in EMX + runtime architecture: + + EMX.DLL is *not* initialized from its _DLL_InitTerm() + routine, but the initialization is postponed until + immediately before main() is called by the principal + executable (may be the initialization also happens during + InitTerm of -Zso -Zsys DLLs?). The only reason I can see is + to postpone the initialization until the "layout" structure + is available, so the type of the executable is known. + [Instead, one should have broken the initialization into two + steps, with no-layout-known initialization ASAP, and the + finishing touch done when "layout" is known.] + + It is due to this hack that -Zsys, -Zso etc. are needed so + often. + + If during initialization of the Perl runtime environment we + discover that EMX environment is not set up completely, this + can be because of either our DLL being called from an + uncompatible flavor of EMX executable, or from an + unrelated-to-EMX.DLL (e.g., -Zsys or compiled with a + different compiler) executable. In the first case only the + CRTL is not completely initialized, in the other case + EMX.DLL may be not initialized too. + + We detect which of these two situations takes place, then + explicitly call the initialization entry points of EMX.DLL + and of CRT. The large caveat is that the init-entry point + of EMX.DLL also moves the stack pointer (another defect of + EMX architecture, the init() and + set_exception_handlers_on_stack() entry points should have + been separated). Thus we need some inline-assembler to + compensate for this, and need to remove the installed + exception handler - it is useless anyway, since exception + handlers need to be on the stack. [This one is on the + stack, but will be overwritten on exit from the function.] + + We also install an extra hack to run our atexit() handlers + on termination of the process (since the principal + executable does not know about *this* CRTL, we need to do it + ourselves - and longjmp() out of the chain of exception + handlers at a proper moment :-(). + + The net result: Perl DLL can be now used with an arbitrary + application. PERLREXX DLL is provided which makes Perl usable + from any REXX-enabled application. + + New test targets added to test how well Perl DLL runs with + different flavors of executables (see all_harness etc). To + avoid waiting for the user button press, run with env + PERL_TEST_NOVREXX=1. + + Another hack: on init of Perl runtime environment, the + executable is tested for being an aout EMX executable. The + test is the same done by gdb, so although this test is very + voodoo, it should be pretty robust (the beginning of the + executable code - at 0x10000 - is tested for a known bit + pattern). The result is used to set $OS2::can_fork, which is + eventually used to set $Config::Config{can_fork}. + + REXX::eval_REXX() made reenterable. ADDRESS PERLEVAL + available for the run REXX code. PERLLASTERROR available. + + A .map file is created for the .dll. Now easier to debug the + failures which do not happen with a debugging executable. + + Duplicate libperl.lib as perl.lib etc. to make Embed happier. + + File::Spec better adjusted to OS/2 (still does not support aa:/dir/). + + New module OS::Process::Const with necessary constants for the + Perl calls which mimic OS/2 API calls. + +After @14577: + $Config{pager} better (but needs work in the binary installer!). + + New API: OS2::DLLname([type], [\&sub]) + + New OS2::Process APIs: + + process_hwnd winTitle_set winTitle swTitle_set bothTitle_set + hWindowPos hWindowPos_set DesktopWindow + ActiveWindow_set + EnableWindow EnableWindowUpdate IsWindowEnabled + IsWindowVisible IsWindowShowing WindowPtr WindowULong + WindowUShort SetWindowBits SetWindowPtr + SetWindowULong + SetWindowUShort MPFROMSHORT MPVOID MPFROMCHAR + MPFROM2SHORT + MPFROMSH2CH MPFROMLONG + + OS::Process::Const symbols exportable from OS::Process too. + + OS::Process: prototypes on subroutines which do not naturally + take "vectors" as arguments (not backwards compatible!). + + New C API: SaveCroakWinError(), WinError_2_Perl_rc, + DeclWinFuncByORD_CACHE(), DeclWinFuncByORD_CACHE_survive(), + DeclWinFuncByORD_CACHE_resetError_survive(), + DeclWinFunc_CACHE(), DeclWinFunc_CACHE_resetError(), + DeclWinFunc_CACHE_survive(), + DeclWinFunc_CACHE_resetError_survive(); many new OS2 entry + points conveniently available via wrappers which will do the + necessary run-time dynalinking. + +After @15047: + + makes PerlIO preserve the binary/text mode of filehandles + chosen by CRT library. (However, TTY handles still are not + clean, since switching them to TERMIO mode and back changes + the NL translation law at runtime, and PerlIO level does not + know this.) diff --git a/gnu/usr.bin/perl/os2/Makefile.SHs b/gnu/usr.bin/perl/os2/Makefile.SHs index c167226cef4..ba3744457f3 100644 --- a/gnu/usr.bin/perl/os2/Makefile.SHs +++ b/gnu/usr.bin/perl/os2/Makefile.SHs @@ -14,6 +14,15 @@ esac dll_post="`echo $perl_fullversion | sum | sed -e 's/^0*//' | awk '{print $1}'`" dll_post="`printf '%x' $dll_post | tr '[a-z]' '[A-Z]'`" +aout_extra_libs='' +aout_extra_sep='' +for xxx in $aout_extra_static_ext; do + aout_extra_dir=`echo "$xxx" | sed -e 's/::/\//g'` + aout_extra_lib="lib/auto/$aout_extra_dir/"`basename "$aout_extra_dir"` + aout_extra_libs="$aout_extra_libs$aout_extra_sep$aout_extra_lib$aout_lib_ext" + aout_extra_sep=' ' +done + $spitshell >>Makefile <<!GROK!THIS! PERL_FULLVERSION = $perl_fullversion @@ -31,20 +40,27 @@ AOUT_LIBPERL_DLL = libperl_dll$aout_lib_ext AOUT_CCCMD_DLL = \$(CC) -DDOSISH -DOS2=2 -DEMBED -I. -DPACK_MALLOC -DDEBUGGING_MSTATS -DTWO_POT_OPTIMIZE -DPERL_EMERGENCY_SBRK AOUT_CLDFLAGS_DLL = -Zexe -Zmt -Zcrtdll -Zstack 32000 -LD_OPT = $optimize +# No -DPERL_CORE +SO_CCCMD = \$(CC) $ccflags \$(OPTIMIZE) + +LD_OPT = \$(OPTIMIZE) +PERL_DLL_LD_OPT = -Zmap -Zlinker /map PERL_DLL_BASE = perl$dll_post PERL_DLL = \$(PERL_DLL_BASE)\$(DLSUFFIX) TEST_PERL_DLL = perl_dll_t CONFIG_ARGS = $config_args +AOUT_EXTRA_LIBS = $aout_extra_libs !GROK!THIS! $spitshell >>Makefile <<'!NO!SUBS!' +PREPLIBRARY_LIBPERL = $(LIBPERL) $(LIBPERL): perl.imp $(PERL_DLL) perl5.def libperl_override.lib emximp -o $(LIBPERL) perl.imp + cp $(LIBPERL) perl.lib -libperl_override.imp: os2/os2add.sym +libperl_override.imp: os2/os2add.sym miniperl ./miniperl -wnle 'print "$$_\t$(PERL_DLL_BASE)\t$$_\t?"' os2/os2add.sym > tmp.imp echo 'strdup $(PERL_DLL_BASE) Perl_strdup ?' >> tmp.imp echo 'putenv $(PERL_DLL_BASE) Perl_putenv ?' >> tmp.imp @@ -63,6 +79,12 @@ perl.imp: perl5.def echo 'emx_malloc emxlibcm 402 ?' >> $@ echo 'emx_realloc emxlibcm 403 ?' >> $@ +.PHONY: perl_dll installcmd aout_clean aout_install aout_install.perl \ + perlrexx test_prep_perl_ test_prep_perl_sys test_prep_perl_stat \ + test_prep_perl_stat_aout test_prep_various \ + stat_aout_harness aout_harness stat_harness sys_harness all_harness \ + stat_aout_test aout_test stat_test sys_test all_test + perl_dll: $(PERL_DLL) perl_dll_t: t/$(PERL_DLL) @@ -71,7 +93,7 @@ t/$(PERL_DLL): $(PERL_DLL) $(LNS) $(PERL_DLL) t/$(PERL_DLL) $(PERL_DLL): $(obj) perl5.def perl$(OBJ_EXT) - $(LD) $(LD_OPT) $(LDDLFLAGS) -o $@ perl$(OBJ_EXT) $(obj) $(libs) perl5.def || ( rm $(PERL_DLL) && sh -c false ) + $(LD) $(LD_OPT) $(LDDLFLAGS) $(PERL_DLL_LD_OPT) -o $@ perl$(OBJ_EXT) $(obj) $(libs) perl5.def || ( rm $(PERL_DLL) && sh -c false ) perl5.olddef: perl.linkexp echo "LIBRARY '$(PERL_DLL_BASE)' INITINSTANCE TERMINSTANCE" > $@ @@ -105,7 +127,11 @@ perl.linkexp: perl.exports perl.map os2/os2.sym # We link miniperl statically, since .DLL depends on $(DYNALOADER) -miniperl.map miniperl: $(obj) perl$(OBJ_EXT) miniperlmain$(OBJ_EXT) opmini$(OBJ_EXT) +miniperl.map: miniperl + +miniperl.exe: miniperl + +miniperl: $(obj) perl$(OBJ_EXT) miniperlmain$(OBJ_EXT) opmini$(OBJ_EXT) $(CC) $(CLDFLAGS) -o miniperl miniperlmain$(OBJ_EXT) perl$(OBJ_EXT) `echo $(obj)|sed -e 's/\bop\./opmini./g'` $(libs) -Zmap -Zlinker /map/PM:VIO @./miniperl -w -Ilib -MExporter -e '<?>' || $(MAKE) minitest @@ -129,29 +155,40 @@ os2thread.h: os2/os2thread.h dlfcn.h: os2/dlfcn.h cp -f $< $@ -# This one is compiled OMF, so cannot fork(): +# Non-Forking dynamically loaded perl -perl___: $& perlmain$(OBJ_EXT) $(LIBPERL) $(DYNALOADER) $(static_ext) ext.libs - $(SHRPENV) $(CC) $(CLDFLAGS) $(CCDLFLAGS) -o perl___ perlmain$(OBJ_EXT) $(DYNALOADER) $(static_ext) $(LIBPERL) `cat ext.libs` $(libs) +perl___$(EXE_EXT) perl___: $& perlmain$(OBJ_EXT) $(LIBPERL) $(DYNALOADER) $(static_ext) ext.libs + $(SHRPENV) $(CC) $(CLDFLAGS) $(CCDLFLAGS) -o perl___ perlmain$(OBJ_EXT) $(DYNALOADER) $(static_ext) $(LIBPERL) `cat ext.libs` $(libs) -Zlinker /map/PM:VIO # This one is compiled -Zsys, so cannot do many things: +# Remove -Zcrtdll +STAT_CLDFLAGS = -Zexe -Zomf -Zmt -Zstack 32000 + +# Non-forking dynamically loaded perl with a wrong CRT library: + +perl_stat: $& perlmain$(OBJ_EXT) $(LIBPERL) $(DYNALOADER) $(static_ext) ext.libs + $(SHRPENV) $(CC) $(STAT_CLDFLAGS) $(CCDLFLAGS) -o $@ perlmain$(OBJ_EXT) $(DYNALOADER) $(static_ext) $(LIBPERL) `cat ext.libs` $(libs) -Zlinker /map/PM:VIO + # Remove -Zcrtdll, add -Zsys -SYS_CLDFLAGS = -Zexe -Zomf -Zmt -Zsys -Zstack 32000 +SYS_CLDFLAGS = $(STAT_CLDFLAGS) -Zsys + +# Non-Forking dynamically loaded perl without EMX - so with wrong CRT library perl_sys: $& perlmain$(OBJ_EXT) $(LIBPERL) $(DYNALOADER) $(static_ext) ext.libs - $(SHRPENV) $(CC) $(SYS_CLDFLAGS) $(CCDLFLAGS) -o perl_sys perlmain$(OBJ_EXT) $(DYNALOADER) $(static_ext) $(LIBPERL) `cat ext.libs` $(libs) + $(SHRPENV) $(CC) $(SYS_CLDFLAGS) $(CCDLFLAGS) -o $@ perlmain$(OBJ_EXT) $(DYNALOADER) $(static_ext) $(LIBPERL) `cat ext.libs` $(libs) -Zlinker /map/PM:VIO installcmd : - perl -e 'die qq{Give the option INSTALLCMDDIR=... to make!} if $$ARGV[0] eq ""' $(INSTALLCMDDIR) - perl os2/perl2cmd.pl $(INSTALLCMDDIR) + @perl -e 'die qq{Give the option INSTALLCMDDIR=... to make!} if $$ARGV[0] eq ""' $(INSTALLCMDDIR) + ./miniperl -Ilib os2/perl2cmd.pl $(INSTALLCMDDIR) # Aout section: aout_obj = $(addsuffix $(AOUT_OBJ_EXT),$(basename $(obj))) AOUT_DYNALOADER = $(addsuffix $(AOUT_LIB_EXT),$(basename $(DYNALOADER))) -aout_static_ext = $(addsuffix $(AOUT_LIB_EXT),$(basename $(dynamic_ext))) -aout_static_lib = $(addsuffix $(LIB_EXT),$(basename $(dynamic_ext))) +aout_ext = $(dynamic_ext) $(AOUT_EXTRA_LIBS) +aout_static_ext = $(addsuffix $(AOUT_LIB_EXT),$(basename $(aout_ext))) +aout_static_lib = $(addsuffix $(LIB_EXT),$(basename $(aout_ext))) aout_static_ext_dll = $(addsuffix $(AOUT_LIB_EXT),$(basename $(static_ext))) DYNALOADER_OBJ = ext/DynaLoader/DynaLoader$(OBJ_EXT) @@ -167,6 +204,7 @@ $(DYNALOADER_OBJ) : $(DYNALOADER) $(AOUT_LIBPERL) : $(aout_obj) perl$(AOUT_OBJ_EXT) rm -f $@ $(AOUT_AR) rcu $@ perl$(AOUT_OBJ_EXT) $(aout_obj) + cp $@ perl.a .c$(AOUT_OBJ_EXT): $(AOUT_CCCMD) $(PLDLFLAGS) -c $*.c @@ -181,20 +219,39 @@ aout_perlmain.c: miniperlmain.c config.sh makefile $(static_ext_autoinit) sh writemain $(DYNALOADER) $(aout_static_lib) > tmp sh mv-if-diff tmp aout_perlmain.c -miniperl_: $& miniperlmain$(AOUT_OBJ_EXT) $(AOUT_LIBPERL) opmini$(AOUT_OBJ_EXT) +_preplibrary = miniperl lib/Config.pm lib/lib.pm lib/re.pm + +miniperl_: $& miniperlmain$(AOUT_OBJ_EXT) $(AOUT_LIBPERL) opmini$(AOUT_OBJ_EXT) $(_preplibrary) $(CC) $(AOUT_CLDFLAGS) $(CCDLFLAGS) -o miniperl_ miniperlmain$(AOUT_OBJ_EXT) opmini$(AOUT_OBJ_EXT) $(AOUT_LIBPERL) $(libs) -perl_: $& aout_perlmain$(AOUT_OBJ_EXT) $(AOUT_LIBPERL) $(AOUT_DYNALOADER) $(aout_static_ext) ext.libs +# Forking statically loaded perl + +# Need a miniperl_ dependency, since $(AOUT_DYNALOADER) is build via implicit +# rules, thus would not rebuild miniperl_ via an explicit rule + +perl_$(EXE_EXT) perl_: $& miniperl_ aout_perlmain$(AOUT_OBJ_EXT) $(AOUT_LIBPERL) $(AOUT_DYNALOADER) $(aout_static_ext) ext.libs $(CC) $(AOUT_CLDFLAGS) $(CCDLFLAGS) -o perl_ aout_perlmain$(AOUT_OBJ_EXT) $(AOUT_DYNALOADER) $(aout_static_ext) $(AOUT_LIBPERL) `cat ext.libs` $(libs) -perl : perl__ perl___ +# Remove -Zcrtdll +STAT_AOUT_CLDFLAGS = -Zexe -Zmt -Zstack 32000 + +# Forking dynamically loaded perl with a wrong CRT library: -perl__: $& perlmain$(OBJ_EXT) $(LIBPERL) $(DYNALOADER) $(static_ext) ext.libs +perl_stat_aout$(EXE_EXT) perl_stat_aout: $& perlmain$(AOUT_OBJ_EXT) $(AOUT_DYNALOADER_OBJ) $(aout_static_ext_dll) $(AOUT_LIBPERL_DLL) ext.libs + $(SHRPENV) $(CC) $(STAT_AOUT_CLDFLAGS) $(CCDLFLAGS) -o $@ perlmain$(AOUT_OBJ_EXT) $(AOUT_DYNALOADER_OBJ) $(aout_static_ext_dll) $(AOUT_LIBPERL_DLL) `cat ext.libs` $(libs) + +PERLREXX_DLL = perlrexx.dll + +perl : perl__ perl___ $(PERLREXX_DLL) + +# Dynamically loaded PM-application perl: + +perl__$(EXE_EXT) perl__: $& perlmain$(OBJ_EXT) $(LIBPERL) $(DYNALOADER) $(static_ext) ext.libs $(CC) $(CLDFLAGS) $(CCDLFLAGS) -o perl__ perlmain$(OBJ_EXT) $(DYNALOADER) $(static_ext) $(LIBPERL) `cat ext.libs` $(libs) -Zlinker /PM:PM # Forking dynamically loaded perl: -perl: $& perlmain$(AOUT_OBJ_EXT) $(AOUT_DYNALOADER_OBJ) $(aout_static_ext_dll) $(AOUT_LIBPERL_DLL) ext.libs +perl$(EXE_EXT) perl: $& perlmain$(AOUT_OBJ_EXT) $(AOUT_DYNALOADER_OBJ) $(aout_static_ext_dll) $(AOUT_LIBPERL_DLL) ext.libs $(CC) $(AOUT_CLDFLAGS_DLL) $(CCDLFLAGS) -o perl perlmain$(AOUT_OBJ_EXT) $(AOUT_DYNALOADER_OBJ) $(aout_static_ext_dll) $(AOUT_LIBPERL_DLL) `cat ext.libs` $(libs) clean: aout_clean @@ -207,60 +264,201 @@ aout_install: perl_ aout_install.perl aout_install.perl: perl_ installperl ./perl_ installperl -aout_test: perl_ - - cd t && (rm -f perl_$(EXE_EXT); $(LNS) ../perl_$(EXE_EXT) perl$(EXE_EXT)) && ./perl TEST </dev/tty +perlrexx: $(PERLREXX_DLL) + @sh -c true + +perlrexx.c: os2/perlrexx.c + @cp -f os2/$@ $@ + +# Remove -Zexe, add -Zdll -Zso. No stack needed +SO_CLDFLAGS = -Zdll -Zso -Zomf -Zmt -Zsys + +# A callable-from-REXX DLL + +$(PERLREXX_DLL): perlrexx$(OBJ_EXT) perlrexx.def + $(SHRPENV) $(CC) $(SO_CLDFLAGS) $(CCDLFLAGS) -o $@ perlrexx$(OBJ_EXT) $(DYNALOADER) $(static_ext) $(LIBPERL) `cat ext.libs` $(libs) perlrexx.def + +perlrexx.def: miniperl $(_preplibrary) + echo "LIBRARY 'perlrexx' INITINSTANCE TERMINSTANCE" > tmp.def + echo "DESCRIPTION '@#perl5-porters@perl.org:`miniperl -Ilib -MConfig -e 'print \$$]'`#@ REXX to Perl `miniperl -Ilib -MConfig -e 'print \$$Config{version}'` interface'" >> tmp.def + echo "EXPORTS" >> tmp.def + echo ' "PERL"' >> tmp.def + echo ' "PERLTERM"' >> tmp.def + echo ' "PERLINIT"' >> tmp.def + echo ' "PERLEXIT"' >> tmp.def + echo ' "PERLEVAL"' >> tmp.def + echo ' "PERLLASTERROR"' >> tmp.def + echo ' "PERLEVALSUBCOMMAND"' >> tmp.def + echo ' "PERLEXPORTALL"' >> tmp.def + echo ' "PERLDROPALL"' >> tmp.def + echo ' "PERLDROPALLEXIT"' >> tmp.def + sh mv-if-diff tmp.def $@ + + +perlrexx$(OBJ_EXT): perlrexx.c + $(SO_CCCMD) $(PLDLFLAGS) -c perlrexx.c + +# To test with harness, one needed to HARNESS_IGNORE_EXITCODE=2 + +# Define to be empty to get a TTY test +REDIR_TEST = 2>&1 | tee 00_$@ -# To test with harness, set HARNESS_BAD_EXITCODE=2 +test_prep_perl_: test_prep_pre miniperl_ ./perl_$(EXE_EXT) + PERL=./perl_ $(MAKE) _test_prep -sys_test: perl_sys - - cd t && (rm -f perl_$(EXE_EXT); $(LNS) ../perl_sys$(EXE_EXT) perl$(EXE_EXT)) && ./perl TEST </dev/tty +test_prep_various: test_prep_pre miniperl $(dynamic_ext) $(TEST_PERL_DLL) -sys_harness: perl_sys - - cd t && (rm -f perl_$(EXE_EXT); $(LNS) ../perl_sys$(EXE_EXT) perl$(EXE_EXT)) && env HARNESS_BAD_EXITCODE=2 ./perl harness </dev/tty +test_prep_perl_sys: test_prep_various ./perl_sys$(EXE_EXT) + PERL=./perl_sys $(MAKE) _test_prep + +test_prep_perl___: test_prep_various ./perl___$(EXE_EXT) + PERL=./perl___ $(MAKE) _test_prep + +test_prep_perl_stat: test_prep_various ./perl_stat$(EXE_EXT) + PERL=./perl_stat $(MAKE) _test_prep + +test_prep_perl_stat_aout: test_prep_various ./perl_stat_aout$(EXE_EXT) + PERL=./perl_stat_aout $(MAKE) _test_prep + +aout_test: test_prep_perl_ + PERL=./perl_ $(MAKE) _test + +aout_harness: test_prep_perl_ + -PERL=./perl_ $(MAKE) TESTFILE=harness _test $(REDIR_TEST) + +sys_test: test_prep_perl_sys + PERL=./perl_sys $(MAKE) _test + +sys_harness: test_prep_perl_sys + -PERL=./perl_sys $(MAKE) TESTFILE=harness _test $(REDIR_TEST) + +stat_test: test_prep_perl_stat + PERL=./perl_stat $(MAKE) _test + +stat_harness: test_prep_perl_stat + -PERL=./perl_stat $(MAKE) TESTFILE=harness _test $(REDIR_TEST) + +stat_aout_test: test_prep_perl_stat_aout + PERL=./perl_stat_aout $(MAKE) _test + +stat_aout_harness: test_prep_perl_stat_aout + -PERL=./perl_stat_aout $(MAKE) TESTFILE=harness _test $(REDIR_TEST) + +perl___test: test_prep_perl___ + PERL=./perl___ $(MAKE) _test + +perl___harness: test_prep_perl___ + -PERL=./perl___ $(MAKE) TESTFILE=harness _test $(REDIR_TEST) + +all_test: test aout_test perl___test sys_test stat_test stat_aout_test + +all_harness: test_harness aout_harness perl___harness sys_harness stat_harness stat_aout_harness !NO!SUBS! -# Now we need to find directories in ./ext/ which are two level deep +# Now we need to find directories in ./ext/ which are up to 3 level deep +# Currently (2001/06) there is no directories 4 levels deep. +# (Only directories so that there is no Makefile.PL some levels up matter.) dirs='' +ddirs='' preci='ext/%/Makefile.aout ' for d in ext/* do - # echo "Checking '$d'..." - f="`echo $d/*/Makefile.PL`" - # SDBFile/sdbm, skip kid makefile - if test ! -e "$d/Makefile.PL" -a ! "$f" = ""; then - dirs="$dirs $d" - preci="$preci $d/%/Makefile.aout" + # echo "...Checking '$d'..." + # skip the kid if the parent exists: cmp SDBFile/sdbm, done by MakeMaker + if test ! -e "$d/Makefile.PL"; then + # Need to treat subdirectories manually + # echo "...Checking subdirs of '$d'..." + d_treated='' + for dd in $d/* + do + if test ! -d $dd; then + continue + fi + if test -e "$dd/Makefile.PL"; then + if test "X$d_treated" = "X"; then + d_treated=1 + # echo "...Found parentless 2-level deep Makefile.PL's in $d/*/:" $d/*/Makefile.PL + dirs="$dirs $d" + preci="$preci $d/%/Makefile.aout" + fi + else + # Need to treat subsubdirectories manually + dd_treated='' + for ddd in $dd/* + do + if test ! -d $ddd; then + continue + fi + if test -e "$ddd/Makefile.PL"; then + if test "X$dd_treated" = "X"; then + dd_treated=1 + # echo "...Found parentless 3-level deep Makefile.PL's in $dd/*/:" $dd/*/Makefile.PL + ddirs="$ddirs $dd" + preci="$preci $dd/%/Makefile.aout" + fi + fi + done + fi + done fi done $spitshell >>Makefile <<!GROK!THIS! .PRECIOUS : $preci +# Set this to FORCE to force a rebuilt of aout extensions + +AOUT_EXTENSIONS_FORCE = + +!GROK!THIS! + +for d in $ddirs +do + # Remove the leading component ext/ + dd=`dirname $d` + pp=`basename $dd` + p=$pp/`basename $d` + $spitshell >>Makefile <<!GROK!THIS! +lib/auto/$p/*/%.a : $d/%/Makefile.aout + @cd $d/\$(basename \$(notdir \$@)) ; make -f Makefile.aout config || echo "\$(MAKE) config failed, continuing anyway..." + cd $d/\$(basename \$(notdir \$@)) ; make -f Makefile.aout LINKTYPE=static CCCDLFLAGS= + +$d/%/Makefile.aout : miniperl_ \$(_preplibrary) \$(AOUT_EXTENSIONS_FORCE) + cd \$(dir \$@) ; ../../../../miniperl_ -I ../../../../lib Makefile.PL FIRST_MAKEFILE=Makefile.aout INSTALLDIRS=perl PERL_CORE=1 + !GROK!THIS! +done + for d in $dirs do p=`basename $d` $spitshell >>Makefile <<!GROK!THIS! -lib/auto/$p/*/%.a : ext/$p/%/Makefile.aout - @cd ext/$p/\$(basename \$(notdir \$@)) ; make -f Makefile.aout config || echo "\$(MAKE) config failed, continuing anyway..." - cd ext/$p/\$(basename \$(notdir \$@)) ; make -f Makefile.aout LINKTYPE=static CCCDLFLAGS= +lib/auto/$p/*/%.a : $d/%/Makefile.aout + @cd $d/\$(basename \$(notdir \$@)) ; make -f Makefile.aout config || echo "\$(MAKE) config failed, continuing anyway..." + cd $d/\$(basename \$(notdir \$@)) ; make -f Makefile.aout LINKTYPE=static CCCDLFLAGS= -$d/%/Makefile.aout : miniperl_ - cd \$(dir \$@) ; ../../../miniperl_ -I ../../../lib Makefile.PL MAKEFILE=Makefile.aout INSTALLDIRS=perl +$d/%/Makefile.aout : miniperl_ \$(_preplibrary) \$(AOUT_EXTENSIONS_FORCE) + cd \$(dir \$@) ; ../../../miniperl_ -I ../../../lib Makefile.PL FIRST_MAKEFILE=Makefile.aout INSTALLDIRS=perl PERL_CORE=1 !GROK!THIS! done +# We need to special-case OS2/DLL/DLL.a, since the recipe above will +# try to find it in ext/OS2/DLL + $spitshell >>Makefile <<'!NO!SUBS!' +lib/auto/OS2/DLL/DLL.a : lib/auto/OS2/REXX/REXX.a + @sh -c true + lib/auto/*/%.a : ext/%/Makefile.aout @cd ext/$(basename $(notdir $@)) ; make -f Makefile.aout config || echo "\$(MAKE) config failed, continuing anyway..." cd ext/$(basename $(notdir $@)) ; make -f Makefile.aout LINKTYPE=static CCCDLFLAGS= -ext/%/Makefile.aout : miniperl_ - cd $(dir $@) ; ../../miniperl_ -I ../../lib Makefile.PL MAKEFILE=Makefile.aout INSTALLDIRS=perl +ext/%/Makefile.aout : miniperl_ $(_preplibrary) $(AOUT_EXTENSIONS_FORCE) + cd $(dir $@) ; ../../miniperl_ -I ../../lib Makefile.PL FIRST_MAKEFILE=Makefile.aout INSTALLDIRS=perl PERL_CORE=1 !NO!SUBS! diff --git a/gnu/usr.bin/perl/os2/OS2/ExtAttr/Makefile.PL b/gnu/usr.bin/perl/os2/OS2/ExtAttr/Makefile.PL index 35680288b8c..0b8837f1530 100644 --- a/gnu/usr.bin/perl/os2/OS2/ExtAttr/Makefile.PL +++ b/gnu/usr.bin/perl/os2/OS2/ExtAttr/Makefile.PL @@ -4,7 +4,7 @@ use ExtUtils::MakeMaker; WriteMakefile( 'NAME' => 'OS2::ExtAttr', 'VERSION_FROM' => 'ExtAttr.pm', # finds $VERSION - MAN3PODS => ' ', # Pods will be built by installman. + MAN3PODS => {}, # Pods will be built by installman. 'LIBS' => [''], # e.g., '-lm' 'DEFINE' => '', # e.g., '-DHAVE_SOMETHING' 'INC' => '', # e.g., '-I/usr/include/other' diff --git a/gnu/usr.bin/perl/os2/OS2/PrfDB/Makefile.PL b/gnu/usr.bin/perl/os2/OS2/PrfDB/Makefile.PL index 39521685dfc..2d4a6a7ae54 100644 --- a/gnu/usr.bin/perl/os2/OS2/PrfDB/Makefile.PL +++ b/gnu/usr.bin/perl/os2/OS2/PrfDB/Makefile.PL @@ -4,7 +4,7 @@ use ExtUtils::MakeMaker; WriteMakefile( 'NAME' => 'OS2::PrfDB', 'VERSION_FROM' => 'PrfDB.pm', # finds $VERSION - MAN3PODS => ' ', # Pods will be built by installman. + MAN3PODS => {}, # Pods will be built by installman. 'LIBS' => [''], # e.g., '-lm' 'DEFINE' => '', # e.g., '-DHAVE_SOMETHING' 'INC' => '', # e.g., '-I/usr/include/other' diff --git a/gnu/usr.bin/perl/os2/OS2/PrfDB/PrfDB.xs b/gnu/usr.bin/perl/os2/OS2/PrfDB/PrfDB.xs index e747fcf3771..bc4661a5d6d 100644 --- a/gnu/usr.bin/perl/os2/OS2/PrfDB/PrfDB.xs +++ b/gnu/usr.bin/perl/os2/OS2/PrfDB/PrfDB.xs @@ -11,8 +11,30 @@ extern "C" { } #endif -#define Prf_Open(pszFileName) SaveWinError(PrfOpenProfile(Perl_hab, (pszFileName))) -#define Prf_Close(hini) (!CheckWinError(PrfCloseProfile(hini))) +#define Prf_Open(pszFileName) SaveWinError(pPrfOpenProfile(Perl_hab, (pszFileName))) +#define Prf_Close(hini) (!CheckWinError(pPrfCloseProfile(hini))) + +BOOL (*pPrfCloseProfile) (HINI hini); +HINI (*pPrfOpenProfile) (HAB hab, PCSZ pszFileName); +BOOL (*pPrfQueryProfile) (HAB hab, PPRFPROFILE pPrfProfile); +BOOL (*pPrfQueryProfileData) (HINI hini, PCSZ pszApp, PCSZ pszKey, PVOID pBuffer, + PULONG pulBufferLength); +/* +LONG (*pPrfQueryProfileInt) (HINI hini, PCSZ pszApp, PCSZ pszKey, LONG sDefault); + */ +BOOL (*pPrfQueryProfileSize) (HINI hini, PCSZ pszApp, PCSZ pszKey, + PULONG pulReqLen); +/* +ULONG (*pPrfQueryProfileString) (HINI hini, PCSZ pszApp, PCSZ pszKey, + PCSZ pszDefault, PVOID pBuffer, ULONG ulBufferLength); + */ +BOOL (*pPrfReset) (HAB hab, __const__ PRFPROFILE *pPrfProfile); +BOOL (*pPrfWriteProfileData) (HINI hini, PCSZ pszApp, PCSZ pszKey, + CPVOID pData, ULONG ulDataLength); +/* +BOOL (*pPrfWriteProfileString) (HINI hini, PCSZ pszApp, PCSZ pszKey, + PCSZ pszData); + */ SV * Prf_Get(pTHX_ HINI hini, PSZ app, PSZ key) { @@ -20,10 +42,10 @@ Prf_Get(pTHX_ HINI hini, PSZ app, PSZ key) { BOOL rc; SV *sv; - if (CheckWinError(PrfQueryProfileSize(hini, app, key, &len))) return &PL_sv_undef; + if (CheckWinError(pPrfQueryProfileSize(hini, app, key, &len))) return &PL_sv_undef; sv = newSVpv("", 0); SvGROW(sv, len + 1); - if (CheckWinError(PrfQueryProfileData(hini, app, key, SvPVX(sv), &len)) + if (CheckWinError(pPrfQueryProfileData(hini, app, key, SvPVX(sv), &len)) || (len == 0 && (app == NULL || key == NULL))) { /* Somewhy needed. */ SvREFCNT_dec(sv); return &PL_sv_undef; @@ -37,12 +59,12 @@ I32 Prf_GetLength(HINI hini, PSZ app, PSZ key) { U32 len; - if (CheckWinError(PrfQueryProfileSize(hini, app, key, &len))) return -1; + if (CheckWinError(pPrfQueryProfileSize(hini, app, key, &len))) return -1; return len; } #define Prf_Set(hini, app, key, s, l) \ - (!(CheckWinError(PrfWriteProfileData(hini, app, key, s, l)))) + (!(CheckWinError(pPrfWriteProfileData(hini, app, key, s, l)))) #define Prf_System(key) \ ( (key) ? ( (key) == 1 ? HINI_USERPROFILE \ @@ -59,7 +81,7 @@ Prf_Profiles(pTHX) char system[257]; PRFPROFILE info = { 257, user, 257, system}; - if (CheckWinError(PrfQueryProfile(Perl_hab, &info))) return &PL_sv_undef; + if (CheckWinError(pPrfQueryProfile(Perl_hab, &info))) return &PL_sv_undef; if (info.cchUserName > 257 || info.cchSysName > 257) die("Panic: Profile names too long"); av_push(av, newSVpv(user, info.cchUserName - 1)); @@ -78,12 +100,12 @@ Prf_SetUser(pTHX_ SV *sv) if (!SvPOK(sv)) die("User profile name not defined"); if (SvCUR(sv) > 256) die("User profile name too long"); - if (CheckWinError(PrfQueryProfile(Perl_hab, &info))) return 0; + if (CheckWinError(pPrfQueryProfile(Perl_hab, &info))) return 0; if (info.cchSysName > 257) die("Panic: System profile name too long"); info.cchUserName = SvCUR(sv) + 1; info.pszUserName = SvPVX(sv); - return !CheckWinError(PrfReset(Perl_hab, &info)); + return !CheckWinError(pPrfReset(Perl_hab, &info)); } MODULE = OS2::PrfDB PACKAGE = OS2::Prf PREFIX = Prf_ @@ -141,3 +163,11 @@ OUTPUT: BOOT: Acquire_hab(); + AssignFuncPByORD(pPrfQueryProfileSize, ORD_PRF32QUERYPROFILESIZE); + AssignFuncPByORD(pPrfOpenProfile, ORD_PRF32OPENPROFILE); + AssignFuncPByORD(pPrfCloseProfile, ORD_PRF32CLOSEPROFILE); + AssignFuncPByORD(pPrfQueryProfile, ORD_PRF32QUERYPROFILE); + AssignFuncPByORD(pPrfReset, ORD_PRF32RESET); + AssignFuncPByORD(pPrfQueryProfileData, ORD_PRF32QUERYPROFILEDATA); + AssignFuncPByORD(pPrfWriteProfileData, ORD_PRF32WRITEPROFILEDATA); + diff --git a/gnu/usr.bin/perl/os2/OS2/Process/Makefile.PL b/gnu/usr.bin/perl/os2/OS2/Process/Makefile.PL index d3240631646..6a59d1f0135 100644 --- a/gnu/usr.bin/perl/os2/OS2/Process/Makefile.PL +++ b/gnu/usr.bin/perl/os2/OS2/Process/Makefile.PL @@ -1,10 +1,13 @@ use ExtUtils::MakeMaker; + +create_constants(); # Make a module + # See lib/ExtUtils/MakeMaker.pm for details of how to influence # the contents of the Makefile that is written. WriteMakefile( 'NAME' => 'OS2::Process', VERSION_FROM=> 'Process.pm', - MAN3PODS => ' ', # Pods will be built by installman. + MAN3PODS => {}, # Pods will be built by installman. 'LIBS' => [''], # e.g., '-lm' 'DEFINE' => '', # e.g., '-DHAVE_SOMETHING' 'INC' => '', # e.g., '-I/usr/include/other' @@ -12,3 +15,30 @@ WriteMakefile( # _16_Win16SetTitle => 'pmshapi.93', }, ); + +sub create_constants { + return if -d 'Process_constants'; + my $src_dir; + my @try = qw(.. ../.. ../../.. ../../../..); + for (@try) { + $src_dir = $_, last if -d "$_/utils" and -r "$_/utils/h2xs"; + } + warn("Can't find \$PERL_SRC/utils/h2xs in @try, falling back to no constants"), + return unless defined $src_dir; + # Can't name it *::Constants, otherwise constants.xs would overwrite it... + # This produces warnings from PSZ-conversion on WS_* constants. + system $^X, "-I$src_dir/lib", "$src_dir/utils/h2xs", '-fn', 'OS2::Process::Const', + '--skip-exporter', '--skip-autoloader', # too large memory overhead + '--skip-strict', '--skip-warnings', # likewise + '--skip-ppport', # will not work without dynaloading. + # Most useful for OS2::Process: + '-M^(HWND|WM|SC|SWP|WC|PROG|QW|EDI|WS|QWS|QWP|QWL|FF|FI|LS|FS|FCF|BS|MS|TBM|CF|CFI|FID)_', + '-F', '-DINCL_NLS -DINCL_BASE -DINCL_PM', # Define more symbols + 'os2emx.h' # EMX version of OS/2 API + and warn("Can't build module with contants, falling back to no constants"), + return; + rename 'OS2/Process/Const', 'Process_constants' + or warn("Error renaming module, falling back to no constants: $!"), + return; + return 1; +} diff --git a/gnu/usr.bin/perl/os2/OS2/Process/Process.pm b/gnu/usr.bin/perl/os2/OS2/Process/Process.pm index 88de2bfad5f..29e4d9b4333 100644 --- a/gnu/usr.bin/perl/os2/OS2/Process/Process.pm +++ b/gnu/usr.bin/perl/os2/OS2/Process/Process.pm @@ -1,16 +1,33 @@ +package OS2::localMorphPM; +# use strict; + +sub new { + my ($c,$f) = @_; + OS2::MorphPM($f); + # print STDERR ">>>>>\n"; + bless [$f], $c +} +sub DESTROY { + # print STDERR "<<<<<\n"; + OS2::UnMorphPM(shift->[0]) +} + package OS2::Process; -$VERSION = 0.2; +BEGIN { + require Exporter; + require XSLoader; + #require AutoLoader; -require Exporter; -require DynaLoader; -#require AutoLoader; + our @ISA = qw(Exporter); + our $VERSION = "1.0"; + XSLoader::load('OS2::Process', $VERSION); +} -@ISA = qw(Exporter DynaLoader); # Items to export into callers namespace by default. Note: do not export # names by default without a very good reason. Use EXPORT_OK instead. # Do not simply export all your public functions/methods/constants. -@EXPORT = qw( +our @EXPORT = qw( P_BACKGROUND P_DEBUG P_DEFAULT @@ -43,25 +60,98 @@ require DynaLoader; T_VIRTDRV T_PROTDLL T_32BIT + ppid + ppidOf + sidOf + scrsize + scrsize_set process_entry - set_title + process_entries + process_hentry + process_hentries + change_entry + change_entryh + process_hwnd + Title_set + Title + winTitle_set + winTitle + swTitle_set + bothTitle_set + WindowText + WindowText_set + WindowPos + WindowPos_set + hWindowPos + hWindowPos_set + WindowProcess + SwitchToProgram + DesktopWindow + ActiveWindow + ActiveWindow_set + ClassName + FocusWindow + FocusWindow_set + ShowWindow + PostMsg + BeginEnumWindows + EndEnumWindows + GetNextWindow + IsWindow + ChildWindows + out_codepage + out_codepage_set + in_codepage + in_codepage_set + cursor + cursor_set + screen + screen_set + process_codepages + QueryWindow + WindowFromId + WindowFromPoint + EnumDlgItem + EnableWindow + EnableWindowUpdate + IsWindowEnabled + IsWindowVisible + IsWindowShowing + WindowPtr + WindowULong + WindowUShort + SetWindowBits + SetWindowPtr + SetWindowULong + SetWindowUShort + get_title + set_title +); +our @EXPORT_OK = qw( + ResetWinError + MPFROMSHORT + MPVOID + MPFROMCHAR + MPFROM2SHORT + MPFROMSH2CH + MPFROMLONG ); + +our $AUTOLOAD; + sub AUTOLOAD { # This AUTOLOAD is used to 'autoload' constants from the constant() # XS function. If a constant is not found then control is passed # to the AUTOLOAD in AutoLoader. - local($constname); - ($constname = $AUTOLOAD) =~ s/.*:://; - $val = constant($constname, @_ ? $_[0] : 0); + (my $constname = $AUTOLOAD) =~ s/.*:://; + my $val = constant($constname, @_ ? $_[0] : 0); if ($! != 0) { - if ($! =~ /Invalid/) { - $AutoLoader::AUTOLOAD = $AUTOLOAD; - goto &AutoLoader::AUTOLOAD; - } - else { - ($pack,$file,$line) = caller; + if ($! =~ /Invalid/ || $!{EINVAL}) { + die "Unsupported function $AUTOLOAD" + } else { + my ($pack,$file,$line) = caller; die "Your vendor has not defined OS2::Process macro $constname, used at $file line $line. "; } @@ -70,11 +160,184 @@ sub AUTOLOAD { goto &$AUTOLOAD; } -bootstrap OS2::Process; +sub const_import { + require OS2::Process::Const; + my $sym = shift; + my ($err, $val) = OS2::Process::Const::constant($sym); + die $err if $err; + my $p = caller(1); + + # no strict; + + *{"$p\::$sym"} = sub () { $val }; + (); # needed by import() +} + +sub import { + my $class = shift; + my $ini = @_; + @_ = ($class, + map { + /^(HWND|WM|SC|SWP|WC|PROG|QW|EDI|WS|QWS|QWP|QWL|FF|FI|LS|FS|FCF|BS|MS|TBM|CF|CFI|FID)_/ ? const_import($_) : $_ + } @_); + goto &Exporter::import if @_ > 1 or $ini == 0; +} # Preloaded methods go here. -sub get_title () { (process_entry())[0] } +sub Title () { (process_entry())[0] } + +# *Title_set = \&sesmgr_title_set; + +sub swTitle_set_sw { + my ($title, @sw) = @_; + $sw[0] = $title; + change_entry(@sw); +} + +sub swTitle_set ($) { + my (@sw) = process_entry(); + swTitle_set_sw(shift, @sw); +} + +sub winTitle_set_sw { + my ($title, @sw) = @_; + my $h = OS2::localMorphPM->new(0); + WindowText_set $sw[1], $title; +} + +sub winTitle_set ($) { + my (@sw) = process_entry(); + winTitle_set_sw(shift, @sw); +} + +sub winTitle () { + my (@sw) = process_entry(); + my $h = OS2::localMorphPM->new(0); + WindowText $sw[1]; +} + +sub bothTitle_set ($) { + my (@sw) = process_entry(); + my $t = shift; + winTitle_set_sw($t, @sw); + swTitle_set_sw($t, @sw); +} + +sub Title_set ($) { + my $t = shift; + return 1 if sesmgr_title_set($t); + return 0 unless $^E == 372; + my (@sw) = process_entry(); + winTitle_set_sw($t, @sw); + swTitle_set_sw($t, @sw); +} + +sub process_entry { swentry_expand(process_swentry(@_)) } + +our @hentry_fields = qw( title owner_hwnd icon_hwnd + owner_phandle owner_pid owner_sid + visible nonswitchable jumpable ptype sw_entry ); + +sub swentry_hexpand ($) { + my %h; + @h{@hentry_fields} = swentry_expand(shift); + \%h; +} + +sub process_hentry { swentry_hexpand(process_swentry(@_)) } +sub process_hwnd { process_hentry()->{owner_hwnd} } + +my $swentry_size = swentry_size(); + +sub sw_entries () { + my $s = swentries_list(); + my ($c, $s1) = unpack 'La*', $s; + die "Unconsistent size in swentries_list()" unless 4+$c*$swentry_size == length $s; + my (@l, $e); + push @l, $e while $e = substr $s1, 0, $swentry_size, ''; + @l; +} + +sub process_entries () { + map [swentry_expand($_)], sw_entries; +} + +sub process_hentries () { + map swentry_hexpand($_), sw_entries; +} + +sub change_entry { + change_swentry(create_swentry(@_)); +} + +sub create_swentryh ($) { + my $h = shift; + create_swentry(@$h{@hentry_fields}); +} + +sub change_entryh ($) { + change_swentry(create_swentryh(shift)); +} + +# Massage entries into the same order as WindowPos_set: +sub WindowPos ($) { + my ($fl, $h, $w, $y, $x, $behind, $hwnd, @rest) + = unpack 'L l4 L4', WindowSWP(shift); + ($x, $y, $fl, $w, $h, $behind, @rest); +} + +# Put them into a hash +sub hWindowPos ($) { + my %h; + @h{ qw(flags height width y x behind hwnd reserved1 reserved2) } + = unpack 'L l4 L4', WindowSWP(shift); + \%h; +} + +my @SWP_keys = ( [qw(width height)], # SWP_SIZE=1 + [qw(x y)], # SWP_MOVE=2 + [qw(behind)] ); # SWP_ZORDER=3 +my %SWP_def; +@SWP_def{ map @$_, @SWP_keys } = (0) x 20; + +# Get them from a hash +sub hWindowPos_set ($$) { + my $hash = shift; + my $hwnd = (@_ ? shift : $hash->{hwnd} ); + my $flags; + if (exists $hash->{flags}) { + $flags = $hash->{flags}; + } else { # Set flags according to existing keys in $hash + $flags = 0; + for my $bit (0..2) { + exists $hash->{$_} and $flags |= (1<<$bit) for @{$SWP_keys[$bit]}; + } + } + for my $bit (0..2) { # Check for required keys + next unless $flags & (1<<$bit); + exists $hash->{$_} + or die sprintf "key $_ required for flags=%#x", $flags + for @{$SWP_keys[$bit]}; + } + my %h = (%SWP_def, flags => $flags, %$hash); # Avoid warnings + my ($x, $y, $fl, $w, $h, $behind) = @h{ qw(x y flags width height behind) }; + WindowPos_set($hwnd, $x, $y, $fl, $w, $h, $behind); +} + +sub ChildWindows (;$) { + my $hm = OS2::localMorphPM->new(0); + my @kids; + my $h = BeginEnumWindows(@_ ? shift : 1); # HWND_DESKTOP + my $w; + push @kids, $w while $w = GetNextWindow $h; + EndEnumWindows $h; + @kids; +} + +# backward compatibility +*set_title = \&Title_set; +*get_title = \&Title; # Autoload methods go after __END__, and are processed by the autosplit program. @@ -83,15 +346,17 @@ __END__ =head1 NAME -OS2::Process - exports constants for system() call on OS2. +OS2::Process - exports constants for system() call, and process control on OS2. =head1 SYNOPSIS use OS2::Process; - $pid = system(P_PM+P_BACKGROUND, "epm.exe"); + $pid = system(P_PM | P_BACKGROUND, "epm.exe"); =head1 DESCRIPTION +=head2 Optional argument to system() + the builtin function system() under OS/2 allows an optional first argument which denotes the mode of the process. Note that this argument is recognized only if it is strictly numerical. @@ -123,14 +388,21 @@ and optionally add PM and session option bits: =head2 Access to process properties -Additionaly, subroutines my_type(), process_entry() and -C<file_type(file)>, get_title() and C<set_title(newtitle)> are implemented. -my_type() returns the type of the current process (one of -"FS", "DOS", "VIO", "PM", "DETACH" and "UNKNOWN"), or C<undef> on error. +On OS/2 processes have the usual I<parent/child> semantic; +additionally, there is a hierarchy of sessions with their own +I<parent/child> tree. A session is either a FS session, or a windowed +pseudo-session created by PM. A session is a "unit of user +interaction", a change to in/out settings in one of them does not +affect other sessions. =over -=item C<file_type(file)> +=item my_type() + +returns the type of the current process (one of +"FS", "DOS", "VIO", "PM", "DETACH" and "UNKNOWN"), or C<undef> on error. + +=item C<file_type(file)> returns the type of the executable file C<file>, or dies on error. The bits 0-2 of the result contain one of the values @@ -139,15 +411,15 @@ dies on error. The bits 0-2 of the result contain one of the values =item C<T_NOTSPEC> (0) -Application type is not specified in the executable header. +Application type is not specified in the executable header. =item C<T_NOTWINDOWCOMPAT> (1) -Application type is not-window-compatible. +Application type is not-window-compatible. =item C<T_WINDOWCOMPAT> (2) -Application type is window-compatible. +Application type is window-compatible. =item C<T_WINDOWAPI> (3) @@ -177,11 +449,11 @@ and 4 will be set to 0. =item C<T_PHYSDRV> (0x40) -Set to 1 if the executable file is a physical device driver. +Set to 1 if the executable file is a physical device driver. =item C<T_VIRTDRV> (0x80) -Set to 1 if the executable file is a virtual device driver. +Set to 1 if the executable file is a virtual device driver. =item C<T_PROTDLL> (0x100) @@ -190,7 +462,7 @@ library module. =item C<T_32BIT> (0x4000) -Set to 1 for 32-bit executable files. +Set to 1 for 32-bit executable files. =back @@ -200,37 +472,127 @@ conditions. If given non-absolute path, will look on C<PATH>, will add extention F<.exe> if no extension is present (add extension F<.> to suppress). +=item C<@list = process_codepages()> + +the first element is the currently active codepage, up to 2 additional +entries specify the system's "prepared codepages": the codepages the +user can switch to. The active codepage of a process is one of the +prepared codepages of the system (if present). + +=item C<process_codepage_set($cp)> + +sets the currently active codepage. [Affects printer output, in/out +codepages of sessions started by this process, and the default +codepage for drawing in PM; is inherited by kids. Does not affect the +out- and in-codepages of the session.] + +=item ppid() + +returns the PID of the parent process. + +=item C<ppidOf($pid = $$)> + +returns the PID of the parent process of $pid. -1 on error. + +=item C<sidOf($pid = $$)> + +returns the session id of the process id $pid. -1 on error. + +=back + +=head2 Control of VIO sessions + +VIO applications are applications running in a text-mode session. + +=over + +=item out_codepage() + +gets code page used for screen output (glyphs). -1 means that a user font +was loaded. + +=item C<out_codepage_set($cp)> + +sets code page used for screen output (glyphs). -1 switches to a preloaded +user font. -2 switches off the preloaded user font. + +=item in_codepage() + +gets code page used for keyboard input. 0 means that a hardware codepage +is used. + +=item C<in_codepage_set($cp)> + +sets code page used for keyboard input. + +=item C<($w, $h) = scrsize()> + +width and height of the given console window in character cells. + +=item C<scrsize_set([$w, ] $h)> + +set height (and optionally width) of the given console window in +character cells. Use 0 size to keep the old size. + +=item C<($s, $e, $w, $a) = cursor()> + +gets start/end lines of the blinking cursor in the charcell, its width +(1 on text modes) and attribute (-1 for hidden, in text modes other +values mean visible, in graphic modes color). + +=item C<cursor_set($s, $e, [$w [, $a]])> + +sets start/end lines of the blinking cursor in the charcell. Negative +values mean percents of the character cell height. + +=item screen() + +gets a buffer with characters and attributes of the screen. + +=item C<screen_set($buffer)> + +restores the screen given the result of screen(). + +=back + +=head2 Control of the process list + +With the exception of Title_set(), all these calls require that PM is +running, they would not work under alternative Session Managers. + +=over + =item process_entry() returns a list of the following data: =over -=item +=item Title of the process (in the C<Ctrl-Esc> list); -=item +=item window handle of switch entry of the process (in the C<Ctrl-Esc> list); -=item +=item window handle of the icon of the process; -=item +=item process handle of the owner of the entry in C<Ctrl-Esc> list; -=item +=item process id of the owner of the entry in C<Ctrl-Esc> list; -=item +=item session id of the owner of the entry in C<Ctrl-Esc> list; -=item +=item whether visible in C<Ctrl-Esc> list; @@ -239,20 +601,20 @@ whether visible in C<Ctrl-Esc> list; whether item cannot be switched to (note that it is not actually grayed in the C<Ctrl-Esc> list)); -=item +=item whether participates in jump sequence; -=item +=item -program type. Possible values are: +program type. Possible values are: - PROG_DEFAULT 0 - PROG_FULLSCREEN 1 - PROG_WINDOWABLEVIO 2 - PROG_PM 3 - PROG_VDM 4 - PROG_WINDOWEDVDM 7 + PROG_DEFAULT 0 + PROG_FULLSCREEN 1 + PROG_WINDOWABLEVIO 2 + PROG_PM 3 + PROG_VDM 4 + PROG_WINDOWEDVDM 7 Although there are several other program types for WIN-OS/2 programs, these do not show up in this field. Instead, the PROG_VDM or @@ -263,31 +625,671 @@ is a windowed WIN-OS/2 program, it runs in a PROG_WINDOWEDVDM session. Likewise, if it's a full-screen WIN-OS/2 program, it runs in a PROG_VDM session. +=item + +switch-entry handle. =back -=item C<set_title(newtitle)> +Optional arguments: the pid and the window-handle of the application running +in the OS/2 session to query. + +=item process_hentry() + +similar to process_entry(), but returns a hash reference, the keys being + + title owner_hwnd icon_hwnd owner_phandle owner_pid owner_sid + visible nonswitchable jumpable ptype sw_entry + +(a copy of the list of keys is in @hentry_fields). + +=item process_entries() + +similar to process_entry(), but returns a list of array reference for all +the elements in the switch list (one controlling C<Ctrl-Esc> window). + +=item process_hentries() + +similar to process_hentry(), but returns a list of hash reference for all +the elements in the switch list (one controlling C<Ctrl-Esc> window). + +=item change_entry() -- does not work with some windows (if the title is set from the start). +changes a process entry, arguments are the same as process_entry() returns. + +=item change_entryh() + +Similar to change_entry(), but takes a hash reference as an argument. + +=item process_hwnd() + +returns the C<owner_hwnd> of the process entry (for VIO windowed processes +this is the frame window of the session). + +=item Title() + +returns the text of the task switch menu entry of the current session. +(There is no way to get this info in non-standard Session Managers. This +implementation is a shortcut via process_entry().) + +=item C<Title_set(newtitle)> + +tries two different interfaces. The Session Manager one does not work +with some windows (if the title is set from the start). This is a limitation of OS/2, in such a case $^E is set to 372 (type help 372 -for a funny - and wrong - explanation ;-). +for a funny - and wrong - explanation ;-). In such cases a +direct-manipulation of low-level entries is used (same as bothTitle_set()). +Keep in mind that some versions of OS/2 leak memory with such a manipulation. + +=item winTitle() + +returns text of the titlebar of the current process' window. + +=item C<winTitle_set(newtitle)> + +sets text of the titlebar of the current process' window. The change does not +affect the text of the switch entry of the current window. + +=item C<swTitle_set(newtitle)> + +sets text of the task switch menu entry of the current process' window. [There +is no API to query this title.] Does it via SwitchEntry interface, +not Session manager interface. The change does not affect the text of the +titlebar of the current window. + +=item C<bothTitle_set(newtitle)> + +sets text of the titlebar and task switch menu of the current process' window +via direct manipulation of the windows' texts. -=item get_title() +=item C<SwitchToProgram($sw_entry)> -is a shortcut implemented via process_entry(). +switch to session given by a switch list handle. + +Use of this function causes another window (and its related windows) +of a PM session to appear on the front of the screen, or a switch to +another session in the case of a non-PM program. In either case, +the keyboard (and mouse for the non-PM case) input is directed to +the new program. =back +=head2 Control of the PM windows + +Some of these API's require sending a message to the specified window. +In such a case the process needs to be a PM process, or to be morphed +to a PM process via OS2::MorphPM(). + +For a temporary morphing to PM use L<OS2::localMorphPM class>. + +Keep in mind that PM windows are engaged in 2 "orthogonal" window +trees, as well as in the z-order list. + +One tree is given by the I<parent/child> relationship. This +relationship affects drawing (child is drawn relative to its parent +(lower-left corner), and the drawing is clipped by the parent's +boundary; parent may request that I<it's> drawing is clipped to be +confined to the outsize of the childs and/or siblings' windows); +hiding; minimizing/restoring; and destroying windows. + +Another tree (not necessarily connected?) is given by I<ownership> +relationship. Ownership relationship assumes cooperation of the +engaged windows via passing messages on "important events"; e.g., +scrollbars send information messages when the "bar" is moved, menus +send messages when an item is selected; frames +move/hide/unhide/minimize/restore/change-z-order-of owned frames when +the owner is moved/etc., and destroy the owned frames (even when these +frames are not descendants) when the owner is destroyed; etc. [An +important restriction on ownership is that owner should be created by +the same thread as the owned thread, so they engage in the same +message queue.] + +Windows may be in many different state: Focused (take keyboard events) or not, +Activated (=Frame windows in the I<parent/child> tree between the root and +the window with the focus; usually indicate such "active state" by titlebar +highlights, and take mouse events) or not, Enabled/Disabled (this influences +the ability to update the graphic, and may change appearance, as for +enabled/disabled buttons), Visible/Hidden, Minimized/Maximized/Restored, Modal +or not, etc. + +The APIs below all die() on error with the message being $^E. + +=over + +=item C<WindowText($hwnd)> + +gets "a text content" of a window. Requires (morphing to) PM. + +=item C<WindowText_set($hwnd, $text)> + +sets "a text content" of a window. Requires (morphing to) PM. + +=item C<($x, $y, $flags, $width, $height, $behind, @rest) = WindowPos($hwnd)> + +gets window position info as 8 integers (of C<SWP>), in the order suitable +for WindowPos_set(). @rest is marked as "reserved" in PM docs. $flags +is a combination of C<SWP_*> constants. + +=item C<$hash = hWindowPos($hwnd)> + +gets window position info as a hash reference; the keys are C<flags width +height x y behind hwnd reserved1 reserved2>. + +Example: + + exit unless $hash->{flags} & SWP_MAXIMIZE; # Maximized + +=item C<WindowPos_set($hwnd, $x, $y, $flags = SWP_MOVE, $width = 0, $height = 0, $behind = HWND_TOP)> + +Set state of the window: position, size, zorder, show/hide, activation, +minimize/maximize/restore etc. Which of these operations to perform +is governed by $flags. + +=item C<hWindowPos_set($hash, [$hwnd])> + +Same as C<WindowPos_set>, but takes the position from keys C<fl width height +x y behind hwnd> of the hash referenced by $hash. If $hwnd is explicitly +specified, it overrides C<$hash->{hwnd}>. If $hash->{flags} is not specified, +it is calculated basing on the existing keys of $hash. Requires (morphing to) PM. + +Example: + + hWindowPos_set {flags => SWP_MAXIMIZE}, $hwnd; # Maximize + +=item C<($pid, $tid) = WindowProcess($hwnd)> + +gets I<PID> and I<TID> of the process associated to the window. + +=item C<ClassName($hwnd)> + +returns the class name of the window. + +If this window is of any of the preregistered WC_* classes the class +name returned is in the form "#nnnnn", where "nnnnn" is a group +of up to five digits that corresponds to the value of the WC_* class name +constant. + +=item FocusWindow() + +returns the handle of the focus window. Optional argument for specifying +the desktop to use. + +=item C<FocusWindow_set($hwnd)> + +set the focus window by handle. Optional argument for specifying the desktop +to use. E.g, the first entry in program_entries() is the C<Ctrl-Esc> list. +To show an application, use either one of + + WinShowWindow( $hwnd, 1 ); + SetFocus( $hwnd ); + SwitchToProgram($switch_handle); + +(Which work with alternative focus-to-front policies?) Requires (morphing to) PM. + +=item C<ActiveWindow([$parentHwnd])> + +gets the active subwindow's handle for $parentHwnd or desktop. +Returns FALSE if none. + +=item C<ActiveWindow_set($hwnd, [$parentHwnd])> + +sets the active subwindow's handle for $parentHwnd or desktop. Requires (morphing to) PM. + +=item C<ShowWindow($hwnd [, $show])> + +Set visible/hidden flag of the window. Default: $show is TRUE. + +=item C<EnableWindowUpdate($hwnd [, $update])> + +Set window visibility state flag for the window for subsequent drawing. +No actual drawing is done at this moment. Use C<ShowWindow($hwnd, $state)> +when redrawing is needed. While update is disabled, changes to the "window +state" do not change the appearence of the window. Default: $update is TRUE. + +(What is manipulated is the bit C<WS_VISIBLE> of the window style.) + +=item C<EnableWindow($hwnd [, $enable])> + +Set the window enabled state. Default: $enable is TRUE. + +Results in C<WM_ENABLED> message sent to the window. Typically, this +would change the appearence of the window. If at the moment of disabling +focus is in the window (or a descendant), focus is lost (no focus anywhere). +If focus is needed, it can be reassigned explicitly later. + +=item IsWindowEnabled(), IsWindowVisible(), IsWindowShowing() + +these functions take $hwnd as an argument. IsWindowEnabled() queries +the state changed by EnableWindow(), IsWindowVisible() the state changed +by ShowWindow(), IsWindowShowing() is true if there is a part of the window +visible on the screen. + +=item C<PostMsg($hwnd, $msg, $mp1, $mp2)> + +post message to a window. The meaning of $mp1, $mp2 is specific for each +message id $msg, they default to 0. E.g., + + use OS2::Process qw(:DEFAULT WM_SYSCOMMAND WM_CONTEXTMENU + WM_SAVEAPPLICATION WM_QUIT WM_CLOSE + SC_MAXIMIZE SC_RESTORE); + $hwnd = process_hentry()->{owner_hwnd}; + # Emulate choosing `Restore' from the window menu: + PostMsg $hwnd, WM_SYSCOMMAND, MPFROMSHORT(SC_RESTORE); # Not immediate + + # Emulate `Show-Contextmenu' (Double-Click-2), two ways: + PostMsg ActiveWindow, WM_CONTEXTMENU; + PostMsg FocusWindow, WM_CONTEXTMENU; + + /* Emulate `Close' */ + PostMsg ActiveWindow, WM_CLOSE; + + /* Same but with some "warnings" to the application */ + $hwnd = ActiveWindow; + PostMsg $hwnd, WM_SAVEAPPLICATION; + PostMsg $hwnd, WM_CLOSE; + PostMsg $hwnd, WM_QUIT; + +In fact, MPFROMSHORT() may be omited above. + +For messages to other processes, messages which take/return a pointer are +not supported. + +=item C<MP*()> + +The functions MPFROMSHORT(), MPVOID(), MPFROMCHAR(), MPFROM2SHORT(), +MPFROMSH2CH(), MPFROMLONG() can be used the same way as from C. Use them +to construct parameters $m1, $m2 to PostMsg(). + +These functions are not exported by default. + +=item C<$eh = BeginEnumWindows($hwnd)> + +starts enumerating immediate child windows of $hwnd in z-order. The +enumeration reflects the state at the moment of BeginEnumWindows() calls; +use IsWindow() to be sure. All the functions in this group require (morphing to) PM. + +=item C<$kid_hwnd = GetNextWindow($eh)> + +gets the next kid in the list. Gets 0 on error or when the list ends. + +=item C<EndEnumWindows($eh)> + +End enumeration and release the list. + +=item C<@list = ChildWindows([$hwnd])> + +returns the list of child windows at the moment of the call. Same remark +as for enumeration interface applies. Defaults to HWND_DESKTOP. +Example of usage: + + sub l { + my ($o,$h) = @_; + printf ' ' x $o . "%#x\n", $h; + l($o+2,$_) for ChildWindows $h; + } + l 0, $HWND_DESKTOP + +=item C<IsWindow($hwnd)> + +true if the window handle is still valid. + +=item C<QueryWindow($hwnd, $type)> + +gets the handle of a related window. $type should be one of C<QW_*> constants. + +=item C<IsChild($hwnd, $parent)> + +return TRUE if $hwnd is a descendant of $parent. + +=item C<WindowFromId($hwnd, $id)> + +return a window handle of a child of $hwnd with the given $id. + + hwndSysMenu = WinWindowFromID(hwndDlg, FID_SYSMENU); + WinSendMsg(hwndSysMenu, MM_SETITEMATTR, + MPFROM2SHORT(SC_CLOSE, TRUE), + MPFROM2SHORT(MIA_DISABLED, MIA_DISABLED)); + +=item C<WindowFromPoint($x, $y [, $hwndParent [, $descedantsToo]])> + +gets a handle of a child of $hwndParent at C<($x,$y)>. If $descedantsToo +(defaulting to 1) then children of children may be returned too. May return +$hwndParent (defaults to desktop) if no suitable children are found, +or 0 if the point is outside the parent. + +$x and $y are relative to $hwndParent. + +=item C<EnumDlgItem($dlgHwnd, $type [, $relativeHwnd])> + +gets a dialog item window handle for an item of type $type of $dlgHwnd +relative to $relativeHwnd, which is descendant of $dlgHwnd. +$relativeHwnd may be specified if $type is EDI_FIRSTTABITEM or +EDI_LASTTABITEM. + +The return is always an immediate child of hwndDlg, even if hwnd is +not an immediate child window. $type may be + +=over + +=item EDI_FIRSTGROUPITEM + +First item in the same group. + +=item EDI_FIRSTTABITEM + +First item in dialog with style WS_TABSTOP. hwnd is ignored. + +=item EDI_LASTGROUPITEM + +Last item in the same group. + +=item EDI_LASTTABITEM + +Last item in dialog with style WS_TABSTOP. hwnd is ignored. + +=item EDI_NEXTGROUPITEM + +Next item in the same group. Wraps around to beginning of group when +the end of the group is reached. + +=item EDI_NEXTTABITEM + +Next item with style WS_TABSTOP. Wraps around to beginning of dialog +item list when end is reached. + +=item EDI_PREVGROUPITEM + +Previous item in the same group. Wraps around to end of group when the +start of the group is reached. For information on the WS_GROUP style, +see Window Styles. + +=item EDI_PREVTABITEM + +Previous item with style WS_TABSTOP. Wraps around to end of dialog +item list when beginning is reached. + +=back + +=item ResetWinError() + +Resets $^E. One may need to call it before the C<Win*>-class APIs which may +return 0 during normal operation. In such a case one should check both +for return value being zero and $^E being non-zero. The following APIs +do ResetWinError() themselves, thus do not need an explicit one: + + WindowPtr + WindowULong + WindowUShort + WindowTextLength + ActiveWindow + PostMsg + +This function is normally not needed. Not exported by default. + +=back + +=head1 OS2::localMorphPM class + +This class morphs the process to PM for the duration of the given scope. + + { + my $h = OS2::localMorphPM->new(0); + # Do something + } + +The argument has the same meaning as one to OS2::MorphPM(). Calls can +nest with internal ones being NOPs. + +=head1 TODO + +Add tests for: + + SwitchToProgram + ClassName + out_codepage + out_codepage_set + in_codepage + in_codepage_set + cursor + cursor_set + screen + screen_set + process_codepages + QueryWindow + EnumDlgItem + WindowPtr + WindowULong + WindowUShort + SetWindowBits + SetWindowPtr + SetWindowULong + SetWindowUShort + my_type + file_type + scrsize + scrsize_set + +Document: +Query/SetWindowULong/Short/Ptr, SetWindowBits. + +Implement InvalidateRect, +CreateFrameControl. ClipbrdFmtInfo, ClipbrdData, OpenClipbrd, CloseClipbrd, +ClipbrdData_set, EnumClipbrdFmt, EmptyClipbrd. SOMETHINGFROMMR. + + + >But I wish to change the default button if the user enters some + >text into an entryfield. I can detect the entry ok, but can't + >seem to get the button to change to default. + > + >No matter what message I send it, it's being ignored. + + You need to get the style of the buttons using WinQueryWindowULong/QWL_STYLE, + set and reset the BS_DEFAULT bits as appropriate and then use + WinSetWindowULong/QWL_STYLE to set the button style. + Something like this: + hwnd1 = WinWindowFromID (hwnd, id1); + hwnd2 = WinWindowFromID (hwnd, id2); + style1 = WinQueryWindowULong (hwnd1, QWL_STYLE); + style2 = WinQueryWindowULong (hwnd2, QWL_STYLE); + style1 |= style2 & BS_DEFAULT; + style2 &= ~BS_DEFAULT; + WinSetWindowULong (hwnd1, QWL_STYLE, style1); + WinSetWindowULong (hwnd2, QWL_STYLE, style2); + + > How to do query and change a frame creation flags for existing window? + + Set the style bits that correspond to the FCF_* flag for the frame + window and then send a WM_UPDATEFRAME message with the appropriate FCF_* + flag in mp1. + + ULONG ulFrameStyle; + ulFrameStyle = WinQueryWindowULong( WinQueryWindow(hwnd, QW_PARENT), + QWL_STYLE ); + ulFrameStyle = (ulFrameStyle & ~FS_SIZEBORDER) | FS_BORDER; + WinSetWindowULong( WinQueryWindow(hwnd, QW_PARENT), + QWL_STYLE, + ulFrameStyle ); + WinSendMsg( WinQueryWindow(hwnd, QW_PARENT), + WM_UPDATEFRAME, + MPFROMP(FCF_SIZEBORDER), + MPVOID ); + + If the FCF_* flags you want to change does not have a corresponding FS_* + style (i.e. the FCF_* flag corresponds to the presence/lack of a frame + control rather than a property of the frame itself) then you create or + destroy the appropriate control window using the correct FID_* window + identifier and then send the WM_UPDATEFRAME message with the appropriate + FCF_* flag in mp1. + + /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -* + | SetFrameBorder() | + | Changes a frame window's border to the requested type. | + | | + | Parameters on entry: | + | hwndFrame -> Frame window whose border is to be changed. | + | ulBorderStyle -> Type of border to change to. | + | | + | Returns: | + | BOOL -> Success indicator. | + | | + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + BOOL SetFrameBorder( HWND hwndFrame, ULONG ulBorderType ) { + ULONG ulFrameStyle; + BOOL fSuccess = TRUE; + + ulFrameStyle = WinQueryWindowULong( hwndFrame, QWL_STYLE ); + + switch ( ulBorderType ) { + case FS_SIZEBORDER : + ulFrameStyle = (ulFrameStyle & ~(FS_DLGBORDER | FS_BORDER)) + | FS_SIZEBORDER; + break; + + case FS_DLGBORDER : + ulFrameStyle = (ulFrameStyle & ~(FS_SIZEBORDER | FS_BORDER)) + | FS_DLGBORDER; + break; + + case FS_BORDER : + ulFrameStyle = (ulFrameStyle & ~(FS_SIZEBORDER | FS_DLGBORDER)) + | FS_BORDER; + break; + + default : + fSuccess = FALSE; + break; + } // end switch + + if ( fSuccess ) { + fSuccess = WinSetWindowULong( hwndFrame, QWL_STYLE, ulFrameStyle ); + + if ( fSuccess ) { + fSuccess = (BOOL)WinSendMsg( hwndFrame, WM_UPDATEFRAME, 0, 0 ); + if ( fSuccess ) + fSuccess = WinInvalidateRect( hwndFrame, NULL, TRUE ); + } + } + + return ( fSuccess ); + + } // End SetFrameBorder() + + hwndMenu=WinLoadMenu(hwndParent,NULL,WND_IMAGE); + WinSetWindowUShort(hwndMenu,QWS_ID,FID_MENU); + ulStyle=WinQueryWindowULong(hwndMenu,QWL_STYLE); + WinSetWindowULong(hwndMenu,QWL_STYLE,ulStyle|MS_ACTIONBAR); + WinSendMsg(hwndParent,WM_UPDATEFRAME,MPFROMSHORT(FCF_MENU),0L); + + OS/2-windows have another "parent" called the *owner*, + which must be set separately - to get a close relationship: + + WinSetOwner (hwndFrameChild, hwndFrameMain); + + Now your child should move with your main window! + And always stays on top of it.... + + To avoid this, for example for dialogwindows, you can + also "disconnect" this relationship with: + + WinSetWindowBits (hwndFrameChild, QWL_STYLE + , FS_NOMOVEWITHOWNER + , FS_NOMOVEWITHOWNER); + + Adding a button icon later: + + /* switch the button style to BS_MINIICON */ + WinSetWindowBits(hwndBtn, QWL_STYLE, BS_MINIICON, BS_MINIICON) ; + + /* set up button control data */ + BTNCDATA bcd; + bcd.cb = sizeof(BTNCDATA); + bcd.hImage = WinLoadPointer(HWND_DESKTOP, dllHandle, ID_ICON_BUTTON1) ; + bcd.fsCheckState = bcd.fsHiliteState = 0 ; + + + WNDPARAMS wp; + wp.fsStatus = WPM_CTLDATA; + wp.pCtlData = &bcd; + + /* add the icon on the button */ + WinSendMsg(hwndBtn, WM_SETWINDOWPARAMS, (MPARAM)&wp, NULL); + + MO> Can anyone tell what OS/2 expects of an application to be properly + MO> minimized to the desktop? + case WM MINMAXFRAME : + { + BOOL fShow = ! (((PSWP) mp1)->fl & SWP MINIMIZE); + HENUM henum; + + HWND hwndChild; + + WinEnableWindowUpdate ( hwnd, FALSE ); + + for (henum=WinBeginEnumWindows(hwnd); + (hwndChild = WinGetNextWindow (henum)) != 0; ) + WinShowWindow ( hwndChild, fShow ); + + WinEndEnumWindows ( henum ); + WinEnableWindowUpdate ( hwnd, TRUE ); + } + break; + +Why C<hWindowPos DesktopWindow> gives C<< behind => HWND_TOP >>? + +=head1 $^E + +the majority of the APIs of this module set $^E on failure (no matter +whether they die() on failure or not). By the semantic of PM API +which returns something other than a boolean, it is impossible to +distinguish failure from a "normal" 0-return. In such cases C<$^E == +0> indicates an absence of error. + +=head1 EXPORTS + +In addition to symbols described above, the following constants (available +also via module C<OS2::Process::Const>) are exportable. Note that these +symbols live in package C<OS2::Process::Const>, they are not available +by full name through C<OS2::Process>! + + HWND_* Standard (abstract) window handles + WM_* Message ids + SC_* WM_SYSCOMMAND flavor + SWP_* Size/move etc flag + WC_* Standard window classes + PROG_* Program category (PM, VIO etc) + QW_* Query-Window flag + EDI_* Enumerate-Dialog-Item code + WS_* Window Style flag + QWS_* Query-window-UShort offsets + QWP_* Query-window-pointer offsets + QWL_* Query-window-ULong offsets + FF_* Frame-window state flags + FI_* Frame-window information flags + LS_* List box styles + FS_* Frame style + FCF_* Frame creation flags + BS_* Button style + MS_* Menu style + TBM_* Title bar messages? + CF_* Clipboard formats + CFI_* Clipboard storage type + FID_* ids of subwindows of frames + +=head1 BUGS + +whether a given API dies or returns FALSE/empty-list on error may be +confusing. This may change in the future. + =head1 AUTHOR -Andreas Kaiser <ak@ananke.s.bawue.de>, +Andreas Kaiser <ak@ananke.s.bawue.de>, Ilya Zakharevich <ilya@math.ohio-state.edu>. =head1 SEE ALSO -C<spawn*>() system calls. +C<spawn*>() system calls, L<OS2::Proc> and L<OS2::WinObject> modules. =cut diff --git a/gnu/usr.bin/perl/os2/OS2/Process/Process.xs b/gnu/usr.bin/perl/os2/OS2/Process/Process.xs index 16b494d77cc..1e75951c5da 100644 --- a/gnu/usr.bin/perl/os2/OS2/Process/Process.xs +++ b/gnu/usr.bin/perl/os2/OS2/Process/Process.xs @@ -1,12 +1,18 @@ -#include "EXTERN.h" -#include "perl.h" -#include "XSUB.h" - #include <process.h> #define INCL_DOS #define INCL_DOSERRORS +#define INCL_DOSNLS +#define INCL_WINSWITCHLIST +#define INCL_WINWINDOWMGR +#define INCL_WININPUT +#define INCL_VIO +#define INCL_KBD #include <os2.h> +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" + static unsigned long constant(char *name, int arg) { @@ -239,27 +245,194 @@ file_type(char *path) return apptype; } +/* These use different type of wrapper. Good to check wrappers. ;-) */ +/* XXXX This assumes DOS type return type, without SEVERITY?! */ +DeclFuncByORD(HSWITCH, myWinQuerySwitchHandle, ORD_WinQuerySwitchHandle, + (HWND hwnd, PID pid), (hwnd, pid)) +DeclFuncByORD(ULONG, myWinQuerySwitchEntry, ORD_WinQuerySwitchEntry, + (HSWITCH hsw, PSWCNTRL pswctl), (hsw, pswctl)) +DeclFuncByORD(ULONG, myWinSetWindowText, ORD_WinSetWindowText, + (HWND hwnd, char* text), (hwnd, text)) +DeclFuncByORD(BOOL, myWinQueryWindowProcess, ORD_WinQueryWindowProcess, + (HWND hwnd, PPID ppid, PTID ptid), (hwnd, ppid, ptid)) +DeclFuncByORD(ULONG, XmyWinSwitchToProgram, ORD_WinSwitchToProgram, + (HSWITCH hsw), (hsw)) +#define myWinSwitchToProgram(hsw) (!CheckOSError(XmyWinSwitchToProgram(hsw))) + + + +DeclWinFunc_CACHE(HWND, QueryWindow, (HWND hwnd, LONG cmd), (hwnd, cmd)) +DeclWinFunc_CACHE(BOOL, QueryWindowPos, (HWND hwnd, PSWP pswp), + (hwnd, pswp)) +DeclWinFunc_CACHE(LONG, QueryWindowText, + (HWND hwnd, LONG cchBufferMax, PCH pchBuffer), + (hwnd, cchBufferMax, pchBuffer)) +DeclWinFunc_CACHE(LONG, QueryClassName, (HWND hwnd, LONG cchMax, PCH pch), + (hwnd, cchMax, pch)) +DeclWinFunc_CACHE(HWND, QueryFocus, (HWND hwndDesktop), (hwndDesktop)) +DeclWinFunc_CACHE(BOOL, SetFocus, (HWND hwndDesktop, HWND hwndFocus), + (hwndDesktop, hwndFocus)) +DeclWinFunc_CACHE(BOOL, ShowWindow, (HWND hwnd, BOOL fShow), (hwnd, fShow)) +DeclWinFunc_CACHE(BOOL, EnableWindow, (HWND hwnd, BOOL fEnable), + (hwnd, fEnable)) +DeclWinFunc_CACHE(BOOL, SetWindowPos, + (HWND hwnd, HWND hwndInsertBehind, LONG x, LONG y, + LONG cx, LONG cy, ULONG fl), + (hwnd, hwndInsertBehind, x, y, cx, cy, fl)) +DeclWinFunc_CACHE(HENUM, BeginEnumWindows, (HWND hwnd), (hwnd)) +DeclWinFunc_CACHE(BOOL, EndEnumWindows, (HENUM henum), (henum)) +DeclWinFunc_CACHE(BOOL, EnableWindowUpdate, (HWND hwnd, BOOL fEnable), + (hwnd, fEnable)) +DeclWinFunc_CACHE(BOOL, SetWindowBits, + (HWND hwnd, LONG index, ULONG flData, ULONG flMask), + (hwnd, index, flData, flMask)) +DeclWinFunc_CACHE(BOOL, SetWindowPtr, (HWND hwnd, LONG index, PVOID p), + (hwnd, index, p)) +DeclWinFunc_CACHE(BOOL, SetWindowULong, (HWND hwnd, LONG index, ULONG ul), + (hwnd, index, ul)) +DeclWinFunc_CACHE(BOOL, SetWindowUShort, (HWND hwnd, LONG index, USHORT us), + (hwnd, index, us)) +DeclWinFunc_CACHE(HWND, IsChild, (HWND hwnd, HWND hwndParent), + (hwnd, hwndParent)) +DeclWinFunc_CACHE(HWND, WindowFromId, (HWND hwnd, ULONG id), (hwnd, id)) +DeclWinFunc_CACHE(HWND, EnumDlgItem, (HWND hwndDlg, HWND hwnd, ULONG code), + (hwndDlg, hwnd, code)) +DeclWinFunc_CACHE(HWND, QueryDesktopWindow, (HAB hab, HDC hdc), (hab, hdc)); +DeclWinFunc_CACHE(BOOL, SetActiveWindow, (HWND hwndDesktop, HWND hwnd), + (hwndDesktop, hwnd)); + +/* These functions may return 0 on success; check $^E/Perl_rc on res==0: */ +DeclWinFunc_CACHE_resetError(PVOID, QueryWindowPtr, (HWND hwnd, LONG index), + (hwnd, index)) +DeclWinFunc_CACHE_resetError(ULONG, QueryWindowULong, (HWND hwnd, LONG index), + (hwnd, index)) +DeclWinFunc_CACHE_resetError(SHORT, QueryWindowUShort, (HWND hwnd, LONG index), + (hwnd, index)) +DeclWinFunc_CACHE_resetError(LONG, QueryWindowTextLength, (HWND hwnd), (hwnd)) +DeclWinFunc_CACHE_resetError(HWND, QueryActiveWindow, (HWND hwnd), (hwnd)) +DeclWinFunc_CACHE_resetError(BOOL, PostMsg, + (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2), + (hwnd, msg, mp1, mp2)) +DeclWinFunc_CACHE_resetError(HWND, GetNextWindow, (HENUM henum), (henum)) +DeclWinFunc_CACHE_resetError(BOOL, IsWindowEnabled, (HWND hwnd), (hwnd)) +DeclWinFunc_CACHE_resetError(BOOL, IsWindowVisible, (HWND hwnd), (hwnd)) +DeclWinFunc_CACHE_resetError(BOOL, IsWindowShowing, (HWND hwnd), (hwnd)) + +/* No die()ing on error */ +DeclWinFunc_CACHE_survive(BOOL, IsWindow, (HAB hab, HWND hwnd), (hab, hwnd)) + +/* These functions are called frow complicated wrappers: */ +ULONG (*pWinQuerySwitchList) (HAB hab, PSWBLOCK pswblk, ULONG usDataLength); +ULONG (*pWinChangeSwitchEntry) (HSWITCH hsw, __const__ SWCNTRL *pswctl); +HWND (*pWinWindowFromPoint)(HWND hwnd, __const__ POINTL *pptl, BOOL fChildren); + + +/* These functions have different names/signatures than what is + declared above */ +#define QueryFocusWindow QueryFocus +#define FocusWindow_set(hwndFocus, hwndDesktop) SetFocus(hwndDesktop, hwndFocus) +#define WindowPos_set(hwnd, x, y, fl, cx, cy, hwndInsertBehind) \ + SetWindowPos(hwnd, hwndInsertBehind, x, y, cx, cy, fl) +#define myWinQueryWindowPtr(hwnd, i) ((ULONG)QueryWindowPtr(hwnd, i)) + +int +WindowText_set(HWND hwnd, char* text) +{ + return !CheckWinError(myWinSetWindowText(hwnd, text)); +} + +SV * +myQueryWindowText(HWND hwnd) +{ + LONG l = QueryWindowTextLength(hwnd), len; + SV *sv; + STRLEN n_a; + + if (l == 0) { + if (Perl_rc) /* Last error */ + return &PL_sv_undef; + return &PL_sv_no; + } + sv = newSVpvn("", 0); + SvGROW(sv, l + 1); + len = WinQueryWindowText(hwnd, l + 1, SvPV_force(sv, n_a)); + if (len != l) { + Safefree(sv); + croak("WinQueryWindowText() uncompatible with WinQueryWindowTextLength()"); + } + SvCUR_set(sv, l); + return sv; +} + +SWP +QueryWindowSWP_(HWND hwnd) +{ + SWP swp; + + if (!QueryWindowPos(hwnd, &swp)) + croak("WinQueryWindowPos() error"); + return swp; +} + +SV * +QueryWindowSWP(HWND hwnd) +{ + SWP swp = QueryWindowSWP_(hwnd); + + return newSVpvn((char*)&swp, sizeof(swp)); +} + +SV * +myQueryClassName(HWND hwnd) +{ + SV *sv = newSVpvn("",0); + STRLEN l = 46, len = 0, n_a; + + while (l + 1 >= len) { + if (len) + len = 2*len + 10; /* Grow quick */ + else + len = l + 2; + SvGROW(sv, len); + l = QueryClassName(hwnd, len, SvPV_force(sv, n_a)); + } + SvCUR_set(sv, l); + return sv; +} + +HWND +WindowFromPoint(long x, long y, HWND hwnd, BOOL fChildren) +{ + POINTL ppl; + + ppl.x = x; ppl.y = y; + if (!pWinWindowFromPoint) + AssignFuncPByORD(pWinWindowFromPoint, ORD_WinWindowFromPoint); + return SaveWinError(pWinWindowFromPoint(hwnd, &ppl, fChildren)); +} + static void -fill_swcntrl(SWCNTRL *swcntrlp) +fill_swentry(SWENTRY *swentryp, HWND hwnd, PID pid) { int rc; - PTIB ptib; - PPIB ppib; HSWITCH hSwitch; - HWND hwndMe; if (!(_emx_env & 0x200)) croak("switch_entry not implemented on DOS"); /* not OS/2. */ - if (CheckOSError(DosGetInfoBlocks(&ptib, &ppib))) - croak("DosGetInfoBlocks err %ld", rc); if (CheckWinError(hSwitch = - WinQuerySwitchHandle(NULLHANDLE, - (PID)ppib->pib_ulpid))) - croak("WinQuerySwitchHandle err %ld", Perl_rc); - if (CheckOSError(WinQuerySwitchEntry(hSwitch, swcntrlp))) + myWinQuerySwitchHandle(hwnd, pid))) + croak("WinQuerySwitchHandle: %s", os2error(Perl_rc)); + swentryp->hswitch = hSwitch; + if (CheckOSError(myWinQuerySwitchEntry(hSwitch, &swentryp->swctl))) croak("WinQuerySwitchEntry err %ld", rc); } +static void +fill_swentry_default(SWENTRY *swentryp) +{ + fill_swentry(swentryp, NULLHANDLE, getpid()); +} + /* static ULONG (* APIENTRY16 pDosSmSetTitle)(ULONG, PSZ); */ ULONG _THUNK_FUNCTION(DosSmSetTitle)(ULONG, PSZ); @@ -267,14 +440,14 @@ ULONG _THUNK_FUNCTION(DosSmSetTitle)(ULONG, PSZ); static ULONG (*pDosSmSetTitle)(ULONG, PSZ); static void -set_title(char *s) +sesmgr_title_set(char *s) { - SWCNTRL swcntrl; + SWENTRY swentry; static HMODULE hdosc = 0; BYTE buf[20]; long rc; - fill_swcntrl(&swcntrl); + fill_swentry_default(&swentry); if (!pDosSmSetTitle || !hdosc) { if (CheckOSError(DosLoadModule(buf, sizeof buf, "sesmgr", &hdosc))) croak("Cannot load SESMGR: no `%s'", buf); @@ -297,17 +470,15 @@ set_title(char *s) #else /* !0 */ static bool -set_title(char *s) +sesmgr_title_set(char *s) { - SWCNTRL swcntrl; - static HMODULE hdosc = 0; - BYTE buf[20]; + SWENTRY swentry; long rc; - fill_swcntrl(&swcntrl); + fill_swentry_default(&swentry); rc = ((USHORT) (_THUNK_PROLOG (2+4); - _THUNK_SHORT (swcntrl.idSession); + _THUNK_SHORT (swentry.swctl.idSession); _THUNK_FLAT (s); _THUNK_CALL (DosSmSetTitle))); #if 0 @@ -336,8 +507,355 @@ set_title2(char *s) } #endif +SV * +process_swentry(unsigned long pid, unsigned long hwnd) +{ + SWENTRY swentry; + + if (!(_emx_env & 0x200)) + croak("process_swentry not implemented on DOS"); /* not OS/2. */ + fill_swentry(&swentry, hwnd, pid); + return newSVpvn((char*)&swentry, sizeof(swentry)); +} + +SV * +swentries_list() +{ + int num, n = 0; + STRLEN n_a; + PSWBLOCK pswblk; + SV *sv = newSVpvn("",0); + + if (!(_emx_env & 0x200)) + croak("swentries_list not implemented on DOS"); /* not OS/2. */ + if (!pWinQuerySwitchList) + AssignFuncPByORD(pWinQuerySwitchList, ORD_WinQuerySwitchList); + num = pWinQuerySwitchList(0, NULL, 0); /* HAB is not required */ + if (!num) + croak("(Unknown) error during WinQuerySwitchList()"); + /* Allow one extra entry to allow overflow detection (may happen + if the list has been changed). */ + while (num > n) { + if (n == 0) + n = num + 1; + else + n = 2*num + 10; /* Enlarge quickly */ + SvGROW(sv, sizeof(ULONG) + sizeof(SWENTRY) * n + 1); + pswblk = (PSWBLOCK) SvPV_force(sv, n_a); + num = pWinQuerySwitchList(0, pswblk, SvLEN(sv)); + } + SvCUR_set(sv, sizeof(ULONG) + sizeof(SWENTRY) * num); + *SvEND(sv) = 0; + return sv; +} + +SWENTRY +swentry( char *title, HWND sw_hwnd, HWND icon_hwnd, HPROGRAM owner_phandle, + PID owner_pid, ULONG owner_sid, ULONG visible, ULONG nonswitchable, + ULONG jumpable, ULONG ptype, HSWITCH sw_entry) +{ + SWENTRY e; + + strncpy(e.swctl.szSwtitle, title, MAXNAMEL); + e.swctl.szSwtitle[60] = 0; + e.swctl.hwnd = sw_hwnd; + e.swctl.hwndIcon = icon_hwnd; + e.swctl.hprog = owner_phandle; + e.swctl.idProcess = owner_pid; + e.swctl.idSession = owner_sid; + e.swctl.uchVisibility = ((visible ? SWL_VISIBLE : SWL_INVISIBLE) + | (nonswitchable ? SWL_GRAYED : 0)); + e.swctl.fbJump = (jumpable ? SWL_JUMPABLE : 0); + e.swctl.bProgType = ptype; + e.hswitch = sw_entry; + return e; +} + +SV * +create_swentry( char *title, HWND owner_hwnd, HWND icon_hwnd, HPROGRAM owner_phandle, + PID owner_pid, ULONG owner_sid, ULONG visible, ULONG nonswitchable, + ULONG jumpable, ULONG ptype, HSWITCH sw_entry) +{ + SWENTRY e = swentry(title, owner_hwnd, icon_hwnd, owner_phandle, owner_pid, + owner_sid, visible, nonswitchable, jumpable, ptype, + sw_entry); + + return newSVpvn((char*)&e, sizeof(e)); +} + +int +change_swentrysw(SWENTRY *sw) +{ + ULONG rc; /* For CheckOSError */ + + if (!(_emx_env & 0x200)) + croak("change_entry() not implemented on DOS"); /* not OS/2. */ + if (!pWinChangeSwitchEntry) + AssignFuncPByORD(pWinChangeSwitchEntry, ORD_WinChangeSwitchEntry); + return !CheckOSError(pWinChangeSwitchEntry(sw->hswitch, &sw->swctl)); +} + +int +change_swentry(SV *sv) +{ + STRLEN l; + PSWENTRY pswentry = (PSWENTRY)SvPV(sv, l); + + if (l != sizeof(SWENTRY)) + croak("Wrong structure size %ld!=%ld in change_swentry()", (long)l, (long)sizeof(SWENTRY)); + return change_swentrysw(pswentry); +} + + +#define swentry_size() (sizeof(SWENTRY)) + +void +getscrsize(int *wp, int *hp) +{ + int i[2]; + + _scrsize(i); + *wp = i[0]; + *hp = i[1]; +} + +/* Force vio to not cross 64K-boundary: */ +#define VIO_FROM_VIOB \ + vio = viob; \ + if (!_THUNK_PTR_STRUCT_OK(vio)) \ + vio++ + +bool +scrsize_set(int w, int h) +{ + VIOMODEINFO viob[2], *vio; + ULONG rc; + + VIO_FROM_VIOB; + + if (h == -9999) + h = w, w = 0; + vio->cb = sizeof(*vio); + if (CheckOSError(VioGetMode( vio, 0 ))) + return 0; + + if( w > 0 ) + vio->col = (USHORT)w; + + if( h > 0 ) + vio->row = (USHORT)h; + + vio->cb = 8; + if (CheckOSError(VioSetMode( vio, 0 ))) + return 0; + return 1; +} + +void +cursor(int *sp, int *ep, int *wp, int *ap) +{ + VIOCURSORINFO viob[2], *vio; + ULONG rc; + + VIO_FROM_VIOB; + + if (CheckOSError(VioGetCurType( vio, 0 ))) + croak("VioGetCurType() error"); + + *sp = vio->yStart; + *ep = vio->cEnd; + *wp = vio->cx; + *ep = vio->attr; +} + +bool +cursor__(int is_a) +{ + int s,e,w,a; + + cursor(&s, &e, &w, &a); + if (is_a) + return a; + else + return w; +} + +bool +cursor_set(int s, int e, int w, int a) +{ + VIOCURSORINFO viob[2], *vio; + ULONG rc; + + VIO_FROM_VIOB; + + vio->yStart = s; + vio->cEnd = e; + vio->cx = w; + vio->attr = a; + return !CheckOSError(VioSetCurType( vio, 0 )); +} + +static int +bufsize(void) +{ +#if 1 + VIOMODEINFO viob[2], *vio; + ULONG rc; + + VIO_FROM_VIOB; + + vio->cb = sizeof(*vio); + if (CheckOSError(VioGetMode( vio, 0 ))) + croak("Can't get size of buffer for screen"); +#if 0 /* buf=323552247, full=1118455, partial=0 */ + croak("Lengths: buf=%d, full=%d, partial=%d",vio->buf_length,vio->full_length,vio->partial_length); + return newSVpvn((char*)vio->buf_addr, vio->full_length); +#endif + return vio->col * vio->row * 2; /* How to get bytes/cell? 2 or 4? */ +#else /* 0 */ + int i[2]; + + _scrsize(i); + return i[0]*i[1]*2; +#endif /* 0 */ +} + +SV * +screen(void) +{ + ULONG rc; + USHORT bufl = bufsize(); + char b[(1<<16) * 3]; /* This/3 is enough for 16-bit calls, we need + 2x overhead due to 2 vs 4 issue, and extra + 64K due to alignment logic */ + char *buf = b; + + if (((ULONG)buf) & 0xFFFF) + buf += 0x10000 - (((ULONG)buf) & 0xFFFF); + if ((sizeof(b) - (buf - b)) < 2*bufl) + croak("panic: VIO buffer allocation"); + if (CheckOSError(VioReadCellStr( buf, &bufl, 0, 0, 0 ))) + return &PL_sv_undef; + return newSVpvn(buf,bufl); +} + +bool +screen_set(SV *sv) +{ + ULONG rc; + STRLEN l = SvCUR(sv), bufl = bufsize(); + char b[(1<<16) * 2]; /* This/2 is enough for 16-bit calls, we need + extra 64K due to alignment logic */ + char *buf = b; + + if (((ULONG)buf) & 0xFFFF) + buf += 0x10000 - (((ULONG)buf) & 0xFFFF); + if (!SvPOK(sv) || ((l != bufl) && (l != 2*bufl))) + croak("Wrong size %d of saved screen data", SvCUR(sv)); + if ((sizeof(b) - (buf - b)) < l) + croak("panic: VIO buffer allocation"); + Copy(SvPV(sv,l), buf, bufl, char); + if (CheckOSError(VioWrtCellStr( buf, bufl, 0, 0, 0 ))) + return 0; + return 1; +} + +int +process_codepages() +{ + ULONG cps[4], cp, rc; + + if (CheckOSError(DosQueryCp( sizeof(cps), cps, &cp ))) + croak("DosQueryCp() error"); + return cp; +} + +int +out_codepage() +{ + USHORT cp, rc; + + if (CheckOSError(VioGetCp( 0, &cp, 0 ))) + croak("VioGetCp() error"); + return cp; +} + +bool +out_codepage_set(int cp) +{ + USHORT rc; + + return !(CheckOSError(VioSetCp( 0, cp, 0 ))); +} + +int +in_codepage() +{ + USHORT cp, rc; + + if (CheckOSError(KbdGetCp( 0, &cp, 0 ))) + croak("KbdGetCp() error"); + return cp; +} + +bool +in_codepage_set(int cp) +{ + USHORT rc; + + return !(CheckOSError(KbdSetCp( 0, cp, 0 ))); +} + +bool +process_codepage_set(int cp) +{ + USHORT rc; + + return !(CheckOSError(DosSetProcessCp( cp ))); +} + +int +ppidOf(int pid) +{ + PQTOPLEVEL psi; + int ppid; + + if (!pid) + return -1; + psi = get_sysinfo(pid, QSS_PROCESS); + if (!psi) + return -1; + ppid = psi->procdata->ppid; + Safefree(psi); + return ppid; +} + +int +sidOf(int pid) +{ + PQTOPLEVEL psi; + int sid; + + if (!pid) + return -1; + psi = get_sysinfo(pid, QSS_PROCESS); + if (!psi) + return -1; + sid = psi->procdata->sessid; + Safefree(psi); + return sid; +} + +#define ulMPFROMSHORT(i) ((unsigned long)MPFROMSHORT(i)) +#define ulMPVOID() ((unsigned long)MPVOID) +#define ulMPFROMCHAR(i) ((unsigned long)MPFROMCHAR(i)) +#define ulMPFROM2SHORT(x1,x2) ((unsigned long)MPFROM2SHORT(x1,x2)) +#define ulMPFROMSH2CH(s, c1, c2) ((unsigned long)MPFROMSH2CH(s, c1, c2)) +#define ulMPFROMLONG(x) ((unsigned long)MPFROMLONG(x)) + MODULE = OS2::Process PACKAGE = OS2::Process +PROTOTYPES: ENABLE unsigned long constant(name,arg) @@ -351,26 +869,265 @@ U32 file_type(path) char *path -U32 -process_entry() +SV * +swentry_expand( SV *sv ) PPCODE: { - SWCNTRL swcntrl; - - fill_swcntrl(&swcntrl); - EXTEND(sp,9); - PUSHs(sv_2mortal(newSVpv(swcntrl.szSwtitle, 0))); - PUSHs(sv_2mortal(newSVnv(swcntrl.hwnd))); - PUSHs(sv_2mortal(newSVnv(swcntrl.hwndIcon))); - PUSHs(sv_2mortal(newSViv(swcntrl.hprog))); - PUSHs(sv_2mortal(newSViv(swcntrl.idProcess))); - PUSHs(sv_2mortal(newSViv(swcntrl.idSession))); - PUSHs(sv_2mortal(newSViv(swcntrl.uchVisibility != SWL_INVISIBLE))); - PUSHs(sv_2mortal(newSViv(swcntrl.uchVisibility == SWL_GRAYED))); - PUSHs(sv_2mortal(newSViv(swcntrl.fbJump == SWL_JUMPABLE))); - PUSHs(sv_2mortal(newSViv(swcntrl.bProgType))); + STRLEN l; + PSWENTRY pswentry = (PSWENTRY)SvPV(sv, l); + + if (l != sizeof(SWENTRY)) + croak("Wrong structure size %ld!=%ld in swentry_expand()", (long)l, (long)sizeof(SWENTRY)); + EXTEND(sp,11); + PUSHs(sv_2mortal(newSVpv(pswentry->swctl.szSwtitle, 0))); + PUSHs(sv_2mortal(newSVnv(pswentry->swctl.hwnd))); + PUSHs(sv_2mortal(newSVnv(pswentry->swctl.hwndIcon))); + PUSHs(sv_2mortal(newSViv(pswentry->swctl.hprog))); + PUSHs(sv_2mortal(newSViv(pswentry->swctl.idProcess))); + PUSHs(sv_2mortal(newSViv(pswentry->swctl.idSession))); + PUSHs(sv_2mortal(newSViv(pswentry->swctl.uchVisibility & SWL_VISIBLE))); + PUSHs(sv_2mortal(newSViv(pswentry->swctl.uchVisibility & SWL_GRAYED))); + PUSHs(sv_2mortal(newSViv(pswentry->swctl.fbJump == SWL_JUMPABLE))); + PUSHs(sv_2mortal(newSViv(pswentry->swctl.bProgType))); + PUSHs(sv_2mortal(newSViv(pswentry->hswitch))); } +SV * +create_swentry( char *title, unsigned long sw_hwnd, unsigned long icon_hwnd, unsigned long owner_phandle, unsigned long owner_pid, unsigned long owner_sid, unsigned long visible, unsigned long switchable, unsigned long jumpable, unsigned long ptype, unsigned long sw_entry) +PROTOTYPE: DISABLE + +int +change_swentry( SV *sv ) + bool -set_title(s) +sesmgr_title_set(s) char *s + +SV * +process_swentry(unsigned long pid = getpid(), unsigned long hwnd = NULLHANDLE); + PROTOTYPE: DISABLE + +int +swentry_size() + +SV * +swentries_list() + +void +ResetWinError() + +int +WindowText_set(unsigned long hwndFrame, char *title) + +bool +FocusWindow_set(unsigned long hwndFocus, unsigned long hwndDesktop = HWND_DESKTOP) + +bool +ShowWindow(unsigned long hwnd, bool fShow = TRUE) + +bool +EnableWindow(unsigned long hwnd, bool fEnable = TRUE) + +bool +PostMsg(unsigned long hwnd, unsigned long msg, unsigned long mp1 = 0, unsigned long mp2 = 0) + C_ARGS: hwnd, msg, (MPARAM)mp1, (MPARAM)mp2 + +bool +WindowPos_set(unsigned long hwnd, long x, long y, unsigned long fl = SWP_MOVE, long cx = 0, long cy = 0, unsigned long hwndInsertBehind = HWND_TOP) + PROTOTYPE: DISABLE + +unsigned long +BeginEnumWindows(unsigned long hwnd) + +bool +EndEnumWindows(unsigned long henum) + +unsigned long +GetNextWindow(unsigned long henum) + +bool +IsWindowVisible(unsigned long hwnd) + +bool +IsWindowEnabled(unsigned long hwnd) + +bool +IsWindowShowing(unsigned long hwnd) + +unsigned long +QueryWindow(unsigned long hwnd, long cmd) + +unsigned long +IsChild(unsigned long hwnd, unsigned long hwndParent) + +unsigned long +WindowFromId(unsigned long hwndParent, unsigned long id) + +unsigned long +WindowFromPoint(long x, long y, unsigned long hwnd = HWND_DESKTOP, bool fChildren = TRUE) +PROTOTYPE: DISABLE + +unsigned long +EnumDlgItem(unsigned long hwndDlg, unsigned long code, unsigned long hwnd = NULLHANDLE) + C_ARGS: hwndDlg, hwnd, code + +bool +EnableWindowUpdate(unsigned long hwnd, bool fEnable = TRUE) + +bool +SetWindowBits(unsigned long hwnd, long index, unsigned long flData, unsigned long flMask) + +bool +SetWindowPtr(unsigned long hwnd, long index, unsigned long p) + C_ARGS: hwnd, index, (PVOID)p + +bool +SetWindowULong(unsigned long hwnd, long index, unsigned long i) + +bool +SetWindowUShort(unsigned long hwnd, long index, unsigned short i) + +bool +IsWindow(unsigned long hwnd, unsigned long hab = Acquire_hab()) + C_ARGS: hab, hwnd + +BOOL +ActiveWindow_set(unsigned long hwnd, unsigned long hwndDesktop = HWND_DESKTOP) + CODE: + RETVAL = SetActiveWindow(hwndDesktop, hwnd); + +int +out_codepage() + +bool +out_codepage_set(int cp) + +int +in_codepage() + +bool +in_codepage_set(int cp) + +SV * +screen() + +bool +screen_set(SV *sv) + +SV * +process_codepages() + PPCODE: + { + ULONG cps[4], c, i = 0, rc; + + if (CheckOSError(DosQueryCp( sizeof(cps), cps, &c ))) + c = 0; + c /= sizeof(ULONG); + if (c >= 3) + EXTEND(sp, c); + while (i < c) + PUSHs(sv_2mortal(newSViv(cps[i++]))); + } + +bool +process_codepage_set(int cp) + +void +cursor(OUTLIST int stp, OUTLIST int ep, OUTLIST int wp, OUTLIST int ap) + PROTOTYPE: + +bool +cursor_set(int s, int e, int w = cursor__(0), int a = cursor__(1)) + +MODULE = OS2::Process PACKAGE = OS2::Process PREFIX = myQuery + +SV * +myQueryWindowText(unsigned long hwnd) + +SV * +myQueryClassName(unsigned long hwnd) + +MODULE = OS2::Process PACKAGE = OS2::Process PREFIX = Query + +unsigned long +QueryFocusWindow(unsigned long hwndDesktop = HWND_DESKTOP) + +long +QueryWindowTextLength(unsigned long hwnd) + +SV * +QueryWindowSWP(unsigned long hwnd) + +unsigned long +QueryWindowULong(unsigned long hwnd, long index) + +unsigned short +QueryWindowUShort(unsigned long hwnd, long index) + +unsigned long +QueryActiveWindow(unsigned long hwnd = HWND_DESKTOP) + +unsigned long +QueryDesktopWindow(unsigned long hab = Acquire_hab(), unsigned long hdc = NULLHANDLE) + +MODULE = OS2::Process PACKAGE = OS2::Process PREFIX = myWinQuery + +unsigned long +myWinQueryWindowPtr(unsigned long hwnd, long index) + +NO_OUTPUT BOOL +myWinQueryWindowProcess(unsigned long hwnd, OUTLIST unsigned long pid, OUTLIST unsigned long tid) + PROTOTYPE: $ + POSTCALL: + if (CheckWinError(RETVAL)) + croak("WindowProcess() error"); + +MODULE = OS2::Process PACKAGE = OS2::Process PREFIX = myWin + +int +myWinSwitchToProgram(unsigned long hsw) + PREINIT: + ULONG rc; + +MODULE = OS2::Process PACKAGE = OS2::Process PREFIX = myWinQuery + +MODULE = OS2::Process PACKAGE = OS2::Process PREFIX = get + +int +getppid() + +int +ppidOf(int pid = getpid()) + +int +sidOf(int pid = getpid()) + +void +getscrsize(OUTLIST int wp, OUTLIST int hp) + PROTOTYPE: + +bool +scrsize_set(int w_or_h, int h = -9999) + +MODULE = OS2::Process PACKAGE = OS2::Process PREFIX = ul + +unsigned long +ulMPFROMSHORT(unsigned short i) + +unsigned long +ulMPVOID() + +unsigned long +ulMPFROMCHAR(unsigned char i) + +unsigned long +ulMPFROM2SHORT(unsigned short x1, unsigned short x2) + PROTOTYPE: DISABLE + +unsigned long +ulMPFROMSH2CH(unsigned short s, unsigned char c1, unsigned char c2) + PROTOTYPE: DISABLE + +unsigned long +ulMPFROMLONG(unsigned long x) + diff --git a/gnu/usr.bin/perl/os2/OS2/REXX/Makefile.PL b/gnu/usr.bin/perl/os2/OS2/REXX/Makefile.PL index 46c4697cef5..9b4c0baf255 100644 --- a/gnu/usr.bin/perl/os2/OS2/REXX/Makefile.PL +++ b/gnu/usr.bin/perl/os2/OS2/REXX/Makefile.PL @@ -3,7 +3,7 @@ use ExtUtils::MakeMaker; WriteMakefile( NAME => 'OS2::REXX', VERSION_FROM => 'REXX.pm', - MAN3PODS => ' ', # Pods will be built by installman. + MAN3PODS => {}, # Pods will be built by installman. XSPROTOARG => '-noprototypes', PERL_MALLOC_OK => 1, ); diff --git a/gnu/usr.bin/perl/os2/OS2/REXX/REXX.pm b/gnu/usr.bin/perl/os2/OS2/REXX/REXX.pm index 1a7cb4d54c8..57e6d6d1a43 100644 --- a/gnu/usr.bin/perl/os2/OS2/REXX/REXX.pm +++ b/gnu/usr.bin/perl/os2/OS2/REXX/REXX.pm @@ -12,7 +12,7 @@ require OS2::DLL; # Other items we are prepared to export if requested @EXPORT_OK = qw(drop register); -$VERSION = '1.00'; +$VERSION = '1.01'; # We cannot just put OS2::DLL in @ISA, since some scripts would use # function interface, not method interface... @@ -333,6 +333,67 @@ part of the key and it is subject to character set restrictions. Since REXX is not case-sensitive, the names should be uppercase. +=head1 Subcommand handlers + +By default, the executed REXX code runs without any default subcommand +handler present. A subcommand handler named C<PERLEVAL> is defined, but +not made a default. Use C<ADDRESS PERLEVAL> REXX command to make it a default +handler; alternatively, use C<ADDRESS Handler WhatToDo> to direct a command +to the handler you like. + +Experiments show that the handler C<CMD> is also available; probably it is +provided by the REXX runtime. + +=head1 Interfacing from REXX to Perl + +This module provides an interface from Perl to REXX, and from REXX-inside-Perl +back to Perl. There is an alternative scenario which allows usage of Perl +from inside REXX. + +A DLL F<PerlRexx> provides an API to Perl as REXX functions + + PERL + PERLTERM + PERLINIT + PERLEXIT + PERLEVAL + PERLLASTERROR + PERLEXPORTALL + PERLDROPALL + PERLDROPALLEXIT + +A subcommand handler C<PERLEVALSUBCOMMAND> can also be registered. Calling +the function PERLEXPORTALL() exports all these functions, as well as +exports this subcommand handler under the name C<EVALPERL>. PERLDROPALL() +inverts this action (and unloads PERLEXPORTALL() as well). In particular + + rc = RxFuncAdd("PerlExportAll", 'PerlRexx', "PERLEXPORTALL") + rc = PerlExportAll() + res = PERLEVAL(perlarg) + ADDRESS EVALPERL perlarg1 + rc = PerlDropAllExit() + +loads all the functions above, evals the Perl code in the REXX variable +C<perlarg>, putting the result into the REXX variable C<res>, +then evals the Perl code in the REXX variable C<perlarg1>, and, finally, +drops the loaded functions and the subcommand handler, deinitializes +the Perl interpreter, and exits the Perl's C runtime library. + +PERLEXIT() or PERLDROPALLEXIT() should be called as the last command of +the REXX program. (This is considered as a bug.) Their purpose is to flush +all the output buffers of the Perl's C runtime library. + +C<PERLLASTERROR> gives the reason for the failure of the last PERLEVAL(). +It is useful inside C<signal on syntax> handler. PERLINIT() and PERLTERM() +initialize and deinitialize the Perl interpreter. + +C<PERLEVAL(string)> initializes the Perl interpreter (if needed), and +evaluates C<string> as Perl code. The result is returned to REXX stringified, +undefined result is considered as failure. + +C<PERL(string)> does the same as C<PERLEVAL(string)> wrapped by calls to +PERLINIT() and PERLEXIT(). + =head1 NOTES Note that while function and variable names are case insensitive in the diff --git a/gnu/usr.bin/perl/os2/OS2/REXX/REXX.xs b/gnu/usr.bin/perl/os2/OS2/REXX/REXX.xs index f88d0afbc6a..c3ddcb4dbd0 100644 --- a/gnu/usr.bin/perl/os2/OS2/REXX/REXX.xs +++ b/gnu/usr.bin/perl/os2/OS2/REXX/REXX.xs @@ -25,11 +25,16 @@ static SHVBLOCK * vars; static int nvars; static char * trace; +/* static RXSTRING rxcommand = { 9, "RXCOMMAND" }; static RXSTRING rxsubroutine = { 12, "RXSUBROUTINE" }; static RXSTRING rxfunction = { 11, "RXFUNCTION" }; +*/ static ULONG PERLCALL(PCSZ name, ULONG argc, PRXSTRING argv, PCSZ queue, PRXSTRING ret); +static ULONG PERLCALLcv(PCSZ name, SV *cv, ULONG argc, PRXSTRING argv, PCSZ queue, PRXSTRING ret); +static ULONG PERLSTART(PCSZ name, ULONG argc, PRXSTRING argv, PCSZ queue, PRXSTRING ret); +static RexxSubcomHandler SubCommandPerlEval; #if 1 #define Set RXSHV_SET @@ -41,53 +46,72 @@ static ULONG PERLCALL(PCSZ name, ULONG argc, PRXSTRING argv, PCSZ queue, PRXSTRI #define Drop RXSHV_SYDRO #endif -static long incompartment; +static long incompartment; /* May be used to unload the REXX */ -static SV* -exec_in_REXX(pTHX_ char *cmd, char * handlerName, RexxFunctionHandler *handler) -{ - HMODULE hRexx, hRexxAPI; - BYTE buf[200]; - LONG APIENTRY (*pRexxStart) (LONG, PRXSTRING, PSZ, PRXSTRING, +static LONG APIENTRY (*pRexxStart) (LONG, PRXSTRING, PSZ, PRXSTRING, PSZ, LONG, PRXSYSEXIT, PSHORT, PRXSTRING); - APIRET APIENTRY (*pRexxRegisterFunctionExe) (PSZ, +static APIRET APIENTRY (*pRexxRegisterFunctionExe) (PSZ, RexxFunctionHandler *); - APIRET APIENTRY (*pRexxDeregisterFunction) (PSZ); +static APIRET APIENTRY (*pRexxDeregisterFunction) (PSZ); + +static ULONG (*pRexxVariablePool) (PSHVBLOCK pRequest); + +static SV* exec_cv; + +/* Create a REXX compartment, + register `n' callbacks `handlers' with the REXX names `handlerNames', + evaluate the REXX expression `cmd'. + */ +static SV* +exec_in_REXX_with(pTHX_ char *cmd, int c, char **handlerNames, RexxFunctionHandler **handlers) +{ RXSTRING args[1]; RXSTRING inst[2]; RXSTRING result; USHORT retcode; LONG rc; SV *res; + char *subs = 0; + int n = c; - if (incompartment) - Perl_die(aTHX_ "Attempt to reenter into REXX compartment"); - incompartment = 1; - - if (DosLoadModule(buf, sizeof buf, "REXX", &hRexx) - || DosLoadModule(buf, sizeof buf, "REXXAPI", &hRexxAPI) - || DosQueryProcAddr(hRexx, 0, "RexxStart", (PFN *)&pRexxStart) - || DosQueryProcAddr(hRexxAPI, 0, "RexxRegisterFunctionExe", - (PFN *)&pRexxRegisterFunctionExe) - || DosQueryProcAddr(hRexxAPI, 0, "RexxDeregisterFunction", - (PFN *)&pRexxDeregisterFunction)) { - Perl_die(aTHX_ "REXX not available\n"); - } + incompartment++; - if (handlerName) - pRexxRegisterFunctionExe(handlerName, handler); + if (c) + Newz(728, subs, c, char); + while (n--) { + rc = pRexxRegisterFunctionExe(handlerNames[n], handlers[n]); + if (rc == RXFUNC_DEFINED) + subs[n] = 1; + } MAKERXSTRING(args[0], NULL, 0); MAKERXSTRING(inst[0], cmd, strlen(cmd)); MAKERXSTRING(inst[1], NULL, 0); MAKERXSTRING(result, NULL, 0); - rc = pRexxStart(0, args, "StartPerl", inst, "Perl", RXSUBROUTINE, NULL, + rc = pRexxStart(0, args, /* No arguments */ + "REXX_in_Perl", /* Returned on REXX' PARSE SOURCE, + and the "macrospace function name" */ + inst, /* inst[0] - the code to execute, + inst[1] will contain tokens. */ + "Perl", /* Pass string-cmds to this callback */ + RXSUBROUTINE, /* Many arguments, maybe result */ + NULL, /* No callbacks/exits to register */ &retcode, &result); - incompartment = 0; - pRexxDeregisterFunction("StartPerl"); + incompartment--; + n = c; + while (n--) + if (!subs[n]) + pRexxDeregisterFunction(handlerNames[n]); + if (c) + Safefree(subs); +#if 0 /* Do we want to restore these? */ DosFreeModule(hRexxAPI); DosFreeModule(hRexx); +#endif + + if (RXSTRPTR(inst[1])) /* Free the tokenized version */ + DosFreeMem(RXSTRPTR(inst[1])); if (!RXNULLSTRING(result)) { res = newSVpv(RXSTRPTR(result), RXSTRLEN(result)); DosFreeMem(RXSTRPTR(result)); @@ -97,38 +121,24 @@ exec_in_REXX(pTHX_ char *cmd, char * handlerName, RexxFunctionHandler *handler) if (rc || SvTRUE(GvSV(PL_errgv))) { if (SvTRUE(GvSV(PL_errgv))) { STRLEN n_a; - Perl_die(aTHX_ "Error inside perl function called from REXX compartment:\n%s", SvPV(GvSV(PL_errgv), n_a)) ; + Perl_croak(aTHX_ "Error inside perl function called from REXX compartment:\n%s", SvPV(GvSV(PL_errgv), n_a)) ; } - Perl_die(aTHX_ "REXX compartment returned non-zero status %li", rc); + Perl_croak(aTHX_ "REXX compartment returned non-zero status %li", rc); } return res; } -static SV* exec_cv; - +/* Call the Perl function given by name, or if name=0, by cv, + with the given arguments. Return the stringified result to REXX. */ static ULONG -PERLSTART(PCSZ name, ULONG argc, PRXSTRING argv, PCSZ queue, PRXSTRING ret) -{ - return PERLCALL(NULL, argc, argv, queue, ret); -} - -#define in_rexx_compartment() exec_in_REXX(aTHX_ "return StartPerl()\r\n", \ - "StartPerl", PERLSTART) -#define REXX_call(cv) ( exec_cv = (cv), in_rexx_compartment()) -#define REXX_eval_with(cmd,name,cv) ( exec_cv = (cv), \ - exec_in_REXX(aTHX_ cmd,name,PERLSTART)) -#define REXX_eval(cmd) REXX_eval_with(cmd,NULL,NULL) - -static ULONG -PERLCALL(PCSZ name, ULONG argc, PRXSTRING argv, PCSZ queue, PRXSTRING ret) +PERLCALLcv(PCSZ name, SV *cv, ULONG argc, PRXSTRING argv, PCSZ queue, PRXSTRING ret) { dTHX; EXCEPTIONREGISTRATIONRECORD xreg = { NULL, _emx_exception }; int i, rc; unsigned long len; char *str; - char **arr; SV *res; dSP; @@ -148,14 +158,11 @@ PERLCALL(PCSZ name, ULONG argc, PRXSTRING argv, PCSZ queue, PRXSTRING ret) for (i = 0; i < argc; ++i) XPUSHs(sv_2mortal(newSVpvn(argv[i].strptr, argv[i].strlength))); PUTBACK; - if (name) { + if (name) rc = perl_call_pv(name, G_SCALAR | G_EVAL); - } else if (exec_cv) { - SV *cv = exec_cv; - - exec_cv = NULL; + else if (cv) rc = perl_call_sv(cv, G_SCALAR | G_EVAL); - } else + else rc = -1; SPAGAIN; @@ -182,6 +189,78 @@ PERLCALL(PCSZ name, ULONG argc, PRXSTRING argv, PCSZ queue, PRXSTRING ret) return rc == 1 ? 0 : 1; /* 0 means SUCCESS */ } +static ULONG +PERLSTART(PCSZ name, ULONG argc, PRXSTRING argv, PCSZ queue, PRXSTRING ret) +{ + SV *cv = exec_cv; + + exec_cv = NULL; + return PERLCALLcv(NULL, cv, argc, argv, queue, ret); +} + +static ULONG +PERLCALL(PCSZ name, ULONG argc, PRXSTRING argv, PCSZ queue, PRXSTRING ret) +{ + return PERLCALLcv(name, Nullsv, argc, argv, queue, ret); +} + +RexxFunctionHandler* PF = &PERLSTART; +char* PF_name = "StartPerl"; + +#define REXX_eval_with(cmd,name,cv) \ + ( exec_cv = cv, exec_in_REXX_with(aTHX_ (cmd),1, &(name), &PF)) +#define REXX_call(cv) REXX_eval_with("return StartPerl()\r\n", PF_name, (cv)) +#define REXX_eval(cmd) ( exec_in_REXX_with(aTHX_ (cmd), 0, NULL, NULL)) + +static ULONG +SubCommandPerlEval( + PRXSTRING command, /* command to issue */ + PUSHORT flags, /* error/failure flags */ + PRXSTRING retstr ) /* return code */ +{ + dSP; + STRLEN len; + int ret; + char *str = 0; + SV *in, *res; + + ENTER; + SAVETMPS; + + PUSHMARK(SP); + in = sv_2mortal(newSVpvn(command->strptr, command->strlength)); + eval_sv(in, G_SCALAR); + SPAGAIN; + res = POPs; + PUTBACK; + + ret = 0; + if (SvTRUE(ERRSV)) { + *flags = RXSUBCOM_ERROR; /* raise error condition */ + str = SvPV(ERRSV, len); + } else if (!SvOK(res)) { + *flags = RXSUBCOM_ERROR; /* raise error condition */ + str = "undefined value returned by Perl-in-REXX"; + len = strlen(str); + } else + str = SvPV(res, len); + if (len <= 256 /* Default buffer is 256-char long */ + || !DosAllocMem((PPVOID)&retstr->strptr, len, + PAG_READ|PAG_WRITE|PAG_COMMIT)) { + memcpy(retstr->strptr, str, len); + retstr->strlength = len; + } else { + *flags = RXSUBCOM_ERROR; /* raise error condition */ + strcpy(retstr->strptr, "Not enough memory for the return string of Perl-in-REXX"); + retstr->strlength = strlen(retstr->strptr); + } + + FREETMPS; + LEAVE; + + return 0; /* finished */ +} + static void needstrs(int n) { @@ -207,9 +286,18 @@ needvars(int n) static void initialize(void) { + ULONG rc; + *(PFN *)&pRexxStart = loadByOrdinal(ORD_RexxStart, 1); + *(PFN *)&pRexxRegisterFunctionExe + = loadByOrdinal(ORD_RexxRegisterFunctionExe, 1); + *(PFN *)&pRexxDeregisterFunction + = loadByOrdinal(ORD_RexxDeregisterFunction, 1); + *(PFN *)&pRexxVariablePool = loadByOrdinal(ORD_RexxVariablePool, 1); needstrs(8); needvars(8); trace = getenv("PERL_REXX_DEBUG"); + + rc = RexxRegisterSubcomExe("PERLEVAL", (PFN)&SubCommandPerlEval, NULL); } static int @@ -262,15 +350,15 @@ _set(name,value,...) MAKERXSTRING(var->shvvalue, value, valuelen); if (trace) fprintf(stderr, " %.*s='%.*s'", - var->shvname.strlength, var->shvname.strptr, - var->shvvalue.strlength, var->shvvalue.strptr); + (int)var->shvname.strlength, var->shvname.strptr, + (int)var->shvvalue.strlength, var->shvvalue.strptr); } if (trace) fprintf(stderr, "\n"); vars[n-1].shvnext = NULL; - rc = RexxVariablePool(vars); + rc = pRexxVariablePool(vars); if (trace) - fprintf(stderr, " rc=%X\n", rc); + fprintf(stderr, " rc=%#lX\n", rc); RETVAL = (rc & ~RXSHV_NEWV) ? FALSE : TRUE; } OUTPUT: @@ -303,7 +391,7 @@ _fetch(name, ...) if (trace) fprintf(stderr, "\n"); vars[items-1].shvnext = NULL; - rc = RexxVariablePool(vars); + rc = pRexxVariablePool(vars); if (!(rc & ~RXSHV_NEWV)) { for (i = 0; i < items; ++i) { int namelen; @@ -315,7 +403,7 @@ _fetch(name, ...) namelen = var->shvvaluelen; /* is */ if (trace) fprintf(stderr, " %.*s='%.*s'\n", - var->shvname.strlength, var->shvname.strptr, + (int)var->shvname.strlength, var->shvname.strptr, namelen, var->shvvalue.strptr); if (var->shvret & RXSHV_NEWV || !var->shvvalue.strptr) PUSHs(&PL_sv_undef); @@ -325,7 +413,7 @@ _fetch(name, ...) } } else { if (trace) - fprintf(stderr, " rc=%X\n", rc); + fprintf(stderr, " rc=%#lX\n", rc); } } @@ -351,7 +439,7 @@ _next(stem) DosFreeMem(sv.shvvalue.strptr); MAKERXSTRING(sv.shvvalue, NULL, 0); } - rc = RexxVariablePool(&sv); + rc = pRexxVariablePool(&sv); } while (!rc && memcmp(stem, sv.shvname.strptr, len) != 0); if (!rc) { EXTEND(SP, 2); @@ -377,7 +465,7 @@ _next(stem) die("Error %i when in _next", rc); } else { if (trace) - fprintf(stderr, " rc=%X\n", rc); + fprintf(stderr, " rc=%#lX\n", rc); } } @@ -400,7 +488,7 @@ _drop(name,...) MAKERXSTRING(var->shvvalue, NULL, 0); } vars[items-1].shvnext = NULL; - RETVAL = (RexxVariablePool(vars) & ~RXSHV_NEWV) ? FALSE : TRUE; + RETVAL = (pRexxVariablePool(vars) & ~RXSHV_NEWV) ? FALSE : TRUE; } OUTPUT: RETVAL @@ -409,7 +497,7 @@ int _register(name) char * name CODE: - RETVAL = RexxRegisterFunctionExe(name, PERLCALL); + RETVAL = pRexxRegisterFunctionExe(name, PERLCALL); OUTPUT: RETVAL @@ -427,3 +515,28 @@ REXX_eval_with(cmd,name,cv) char *cmd char *name SV *cv + +#ifdef THIS_IS_NOT_FINISHED + +SV* +_REXX_eval_with(cmd,...) + char *cmd + CODE: + { + int n = (items - 1)/2; + char **names; + SV **cvs; + + if ((items % 2) == 0) + Perl_croak(aTHX_ "Name/values should come in pairs in REXX_eval_with()"); + New(730, names, n, char*); + New(730, cvs, n, SV*); + /* XXX Unfinished... */ + RETVAL = Nullsv; + Safefree(names); + Safefree(cvs); + } + OUTPUT: + RETVAL + +#endif diff --git a/gnu/usr.bin/perl/os2/OS2/REXX/t/rx_cmprt.t b/gnu/usr.bin/perl/os2/OS2/REXX/t/rx_cmprt.t index 6baec7687d0..6db785be515 100644 --- a/gnu/usr.bin/perl/os2/OS2/REXX/t/rx_cmprt.t +++ b/gnu/usr.bin/perl/os2/OS2/REXX/t/rx_cmprt.t @@ -12,7 +12,7 @@ use OS2::REXX qw(:DEFAULT register); $| = 1; # Otherwise data from REXX may come first -print "1..16\n"; +print "1..18\n"; $n = 1; sub do_me { @@ -46,3 +46,9 @@ sub MYFUNC2 {3 * shift} REXX_eval_with "call myfunc say 'ok 'myfunc1(1)myfunc2(2)", myfunc => sub { register qw(myfunc1 myfunc2) }; + +REXX_eval_with "say 'ok 'myfunc(10,7)", + myfunc => sub { REXX_eval "return $_[0] + $_[1]" }; + +sub MyFunc3 {print 'ok ', shift() + shift(), "\n"} +REXX_eval "address perleval\n'MyFunc3(10,8)'"; diff --git a/gnu/usr.bin/perl/os2/OS2/REXX/t/rx_vrexx.t b/gnu/usr.bin/perl/os2/OS2/REXX/t/rx_vrexx.t index b0621f4e229..36118946822 100644 --- a/gnu/usr.bin/perl/os2/OS2/REXX/t/rx_vrexx.t +++ b/gnu/usr.bin/perl/os2/OS2/REXX/t/rx_vrexx.t @@ -3,7 +3,11 @@ BEGIN { @INC = '../lib' if -d 'lib'; require Config; import Config; if (-d 'lib' and $Config{'extensions'} !~ /\bOS2(::|\/)REXX\b/) { - print "1..0\n"; + print "1..0 # skipped: OS2::REXX not built\n"; + exit 0; + } + if (defined $ENV{PERL_TEST_NOVREXX}) { + print "1..0 # skipped: request via PERL_TEST_NOVREXX\n"; exit 0; } } diff --git a/gnu/usr.bin/perl/os2/diff.configure b/gnu/usr.bin/perl/os2/diff.configure index 59a8a5331c5..e69de29bb2d 100644 --- a/gnu/usr.bin/perl/os2/diff.configure +++ b/gnu/usr.bin/perl/os2/diff.configure @@ -1,32 +0,0 @@ ---- Configure.orig Tue Feb 29 19:07:00 2000 -+++ Configure Thu Mar 2 10:10:24 2000 -@@ -1605,6 +1605,11 @@ - esac - fi - if test X"$trnl" = X; then -+ case "`echo foo|tr '\r\n' xy 2>/dev/null`" in -+ fooxy) trnl='\n\r' ;; -+ esac -+fi -+if test X"$trnl" = X; then - cat <<EOM >&2 - - $me: Fatal Error: cannot figure out how to translate newlines with 'tr'. -@@ -1921,7 +1926,7 @@ - *) - echo "I don't know where '$file' is, and my life depends on it." >&4 - echo "Go find a public domain implementation or fix your PATH setting!" >&4 -- exit 1 -+ #exit 1 - ;; - esac - done -@@ -5719,7 +5724,7 @@ - esac - ;; - esac --libnames=''; -+#libnames=''; - case "$libs" in - '') ;; - *) for thislib in $libs; do diff --git a/gnu/usr.bin/perl/os2/dl_os2.c b/gnu/usr.bin/perl/os2/dl_os2.c index aab48dd6729..5c8b6e68716 100644 --- a/gnu/usr.bin/perl/os2/dl_os2.c +++ b/gnu/usr.bin/perl/os2/dl_os2.c @@ -1,4 +1,6 @@ #include "dlfcn.h" +#include "string.h" +#include "stdio.h" #define INCL_BASE #include <os2.h> @@ -6,19 +8,24 @@ static ULONG retcode; static char fail[300]; +char *os2error(int rc); + void * -dlopen(char *path, int mode) +dlopen(const char *path, int mode) { HMODULE handle; char tmp[260], *beg, *dot; ULONG rc; fail[0] = 0; - if ((rc = DosLoadModule(fail, sizeof fail, path, &handle)) == 0) + if ((rc = DosLoadModule(fail, sizeof fail, (char*)path, &handle)) == 0) return (void *)handle; retcode = rc; + if (strlen(path) >= sizeof(tmp)) + return NULL; + /* Not found. Check for non-FAT name and try truncated name. */ /* Don't know if this helps though... */ for (beg = dot = path + strlen(path); @@ -28,6 +35,7 @@ dlopen(char *path, int mode) dot = beg; if (dot - beg > 8) { int n = beg+8-path; + memmove(tmp, path, n); memmove(tmp+n, dot, strlen(dot)+1); if (DosLoadModule(fail, sizeof fail, tmp, &handle) == 0) @@ -38,7 +46,7 @@ dlopen(char *path, int mode) } void * -dlsym(void *handle, char *symbol) +dlsym(void *handle, const char *symbol) { ULONG rc, type; PFN addr; @@ -60,29 +68,17 @@ dlerror(void) { static char buf[700]; ULONG len; + char *err; if (retcode == 0) return NULL; - if (DosGetMessage(NULL, 0, buf, sizeof buf - 1, retcode, - "OSO001.MSG", &len)) { - if (fail[0]) - sprintf(buf, -"OS/2 system error code %d, possible problematic module: '%s'", - retcode, fail); - else - sprintf(buf, "OS/2 system error code %d", retcode); - } else { - buf[len] = '\0'; - if (len && buf[len - 1] == '\n') - buf[--len] = 0; - if (len && buf[len - 1] == '\r') - buf[--len] = 0; - if (len && buf[len - 1] == '.') - buf[--len] = 0; - if (fail[0] && len < 300) - sprintf(buf + len, ", possible problematic module: '%s'", - fail); - } + err = os2error(retcode); + len = strlen(err); + if (len > sizeof(buf) - 1) + len = sizeof(buf) - 1; + strncpy(buf, err, len+1); + if (fail[0] && len < 300) + sprintf(buf + len, ", possible problematic module: '%s'", fail); retcode = 0; return buf; } diff --git a/gnu/usr.bin/perl/os2/dlfcn.h b/gnu/usr.bin/perl/os2/dlfcn.h index c2feee60008..80e5aac52e2 100644 --- a/gnu/usr.bin/perl/os2/dlfcn.h +++ b/gnu/usr.bin/perl/os2/dlfcn.h @@ -1,4 +1,4 @@ -void *dlopen(char *path, int mode); -void *dlsym(void *handle, char *symbol); +void *dlopen(const char *path, int mode); +void *dlsym(void *handle, const char *symbol); char *dlerror(void); int dlclose(void *handle); diff --git a/gnu/usr.bin/perl/os2/os2.c b/gnu/usr.bin/perl/os2/os2.c index 63566c98756..fcf1bfdef0b 100644 --- a/gnu/usr.bin/perl/os2/os2.c +++ b/gnu/usr.bin/perl/os2/os2.c @@ -21,11 +21,15 @@ #include <limits.h> #include <process.h> #include <fcntl.h> +#include <pwd.h> +#include <grp.h> + +#define PERLIO_NOT_STDIO 0 #include "EXTERN.h" #include "perl.h" -#ifdef USE_THREADS +#ifdef USE_5005THREADS typedef void (*emx_startroutine)(void *); typedef void* (*pthreads_startroutine)(void *); @@ -180,89 +184,218 @@ os2_cond_wait(perl_cond *c, perl_mutex *m) } #endif +static int exe_is_aout(void); + /*****************************************************************************/ /* 2.1 would not resolve symbols on demand, and has no ExtLIBPATH. */ -static PFN ExtFCN[2]; /* Labeled by ord below. */ -static USHORT loadOrd[2] = { 874, 873 }; /* Query=874, Set=873. */ -#define ORD_QUERY_ELP 0 -#define ORD_SET_ELP 1 +#define C_ARR_LEN(sym) (sizeof(sym)/sizeof(*sym)) + +struct dll_handle { + const char *modname; + HMODULE handle; +}; +static struct dll_handle doscalls_handle = {"doscalls", 0}; +static struct dll_handle tcp_handle = {"tcp32dll", 0}; +static struct dll_handle pmwin_handle = {"pmwin", 0}; +static struct dll_handle rexx_handle = {"rexx", 0}; +static struct dll_handle rexxapi_handle = {"rexxapi", 0}; +static struct dll_handle sesmgr_handle = {"sesmgr", 0}; +static struct dll_handle pmshapi_handle = {"pmshapi", 0}; + +/* This should match enum entries_ordinals defined in os2ish.h. */ +static const struct { + struct dll_handle *dll; + const char *entryname; + int entrypoint; +} loadOrdinals[ORD_NENTRIES] = { + {&doscalls_handle, NULL, 874}, /* DosQueryExtLibpath */ + {&doscalls_handle, NULL, 873}, /* DosSetExtLibpath */ + {&doscalls_handle, NULL, 460}, /* DosVerifyPidTid */ + {&tcp_handle, "SETHOSTENT", 0}, + {&tcp_handle, "SETNETENT" , 0}, + {&tcp_handle, "SETPROTOENT", 0}, + {&tcp_handle, "SETSERVENT", 0}, + {&tcp_handle, "GETHOSTENT", 0}, + {&tcp_handle, "GETNETENT" , 0}, + {&tcp_handle, "GETPROTOENT", 0}, + {&tcp_handle, "GETSERVENT", 0}, + {&tcp_handle, "ENDHOSTENT", 0}, + {&tcp_handle, "ENDNETENT", 0}, + {&tcp_handle, "ENDPROTOENT", 0}, + {&tcp_handle, "ENDSERVENT", 0}, + {&pmwin_handle, NULL, 763}, /* WinInitialize */ + {&pmwin_handle, NULL, 716}, /* WinCreateMsgQueue */ + {&pmwin_handle, NULL, 726}, /* WinDestroyMsgQueue */ + {&pmwin_handle, NULL, 918}, /* WinPeekMsg */ + {&pmwin_handle, NULL, 915}, /* WinGetMsg */ + {&pmwin_handle, NULL, 912}, /* WinDispatchMsg */ + {&pmwin_handle, NULL, 753}, /* WinGetLastError */ + {&pmwin_handle, NULL, 705}, /* WinCancelShutdown */ + /* These are needed in extensions. + How to protect PMSHAPI: it comes through EMX functions? */ + {&rexx_handle, "RexxStart", 0}, + {&rexx_handle, "RexxVariablePool", 0}, + {&rexxapi_handle, "RexxRegisterFunctionExe", 0}, + {&rexxapi_handle, "RexxDeregisterFunction", 0}, + {&sesmgr_handle, "DOSSMSETTITLE", 0}, /* Would not work runtime-loaded */ + {&pmshapi_handle, "PRF32QUERYPROFILESIZE", 0}, + {&pmshapi_handle, "PRF32OPENPROFILE", 0}, + {&pmshapi_handle, "PRF32CLOSEPROFILE", 0}, + {&pmshapi_handle, "PRF32QUERYPROFILE", 0}, + {&pmshapi_handle, "PRF32RESET", 0}, + {&pmshapi_handle, "PRF32QUERYPROFILEDATA", 0}, + {&pmshapi_handle, "PRF32WRITEPROFILEDATA", 0}, + + /* At least some of these do not work by name, since they need + WIN32 instead of WIN... */ +#if 0 + These were generated with + nm I:\emx\lib\os2.a | fgrep -f API-list | grep = > API-list-entries + perl -wnle "next unless /^0+\s+E\s+_(\w+)=(\w+).(\d+)/; print qq( ORD_$1,)" API-list-entries > API-list-ORD_ + perl -wnle "next unless /^0+\s+E\s+_(\w+)=(\w+).(\d+)/; print qq( {${2}_handle, NULL, $3},\t\t/* $1 */)" WinSwitch-API-list-entries >API-list-entry +#endif + {&pmshapi_handle, NULL, 123}, /* WinChangeSwitchEntry */ + {&pmshapi_handle, NULL, 124}, /* WinQuerySwitchEntry */ + {&pmshapi_handle, NULL, 125}, /* WinQuerySwitchHandle */ + {&pmshapi_handle, NULL, 126}, /* WinQuerySwitchList */ + {&pmshapi_handle, NULL, 131}, /* WinSwitchToProgram */ + {&pmwin_handle, NULL, 702}, /* WinBeginEnumWindows */ + {&pmwin_handle, NULL, 737}, /* WinEndEnumWindows */ + {&pmwin_handle, NULL, 740}, /* WinEnumDlgItem */ + {&pmwin_handle, NULL, 756}, /* WinGetNextWindow */ + {&pmwin_handle, NULL, 768}, /* WinIsChild */ + {&pmwin_handle, NULL, 799}, /* WinQueryActiveWindow */ + {&pmwin_handle, NULL, 805}, /* WinQueryClassName */ + {&pmwin_handle, NULL, 817}, /* WinQueryFocus */ + {&pmwin_handle, NULL, 834}, /* WinQueryWindow */ + {&pmwin_handle, NULL, 837}, /* WinQueryWindowPos */ + {&pmwin_handle, NULL, 838}, /* WinQueryWindowProcess */ + {&pmwin_handle, NULL, 841}, /* WinQueryWindowText */ + {&pmwin_handle, NULL, 842}, /* WinQueryWindowTextLength */ + {&pmwin_handle, NULL, 860}, /* WinSetFocus */ + {&pmwin_handle, NULL, 875}, /* WinSetWindowPos */ + {&pmwin_handle, NULL, 877}, /* WinSetWindowText */ + {&pmwin_handle, NULL, 883}, /* WinShowWindow */ + {&pmwin_handle, NULL, 772}, /* WinIsWindow */ + {&pmwin_handle, NULL, 899}, /* WinWindowFromId */ + {&pmwin_handle, NULL, 900}, /* WinWindowFromPoint */ + {&pmwin_handle, NULL, 919}, /* WinPostMsg */ + {&pmwin_handle, NULL, 735}, /* WinEnableWindow */ + {&pmwin_handle, NULL, 736}, /* WinEnableWindowUpdate */ + {&pmwin_handle, NULL, 773}, /* WinIsWindowEnabled */ + {&pmwin_handle, NULL, 774}, /* WinIsWindowShowing */ + {&pmwin_handle, NULL, 775}, /* WinIsWindowVisible */ + {&pmwin_handle, NULL, 839}, /* WinQueryWindowPtr */ + {&pmwin_handle, NULL, 843}, /* WinQueryWindowULong */ + {&pmwin_handle, NULL, 844}, /* WinQueryWindowUShort */ + {&pmwin_handle, NULL, 874}, /* WinSetWindowBits */ + {&pmwin_handle, NULL, 876}, /* WinSetWindowPtr */ + {&pmwin_handle, NULL, 878}, /* WinSetWindowULong */ + {&pmwin_handle, NULL, 879}, /* WinSetWindowUShort */ + {&pmwin_handle, NULL, 813}, /* WinQueryDesktopWindow */ + {&pmwin_handle, NULL, 851}, /* WinSetActiveWindow */ + {&doscalls_handle, NULL, 360}, /* DosQueryModFromEIP */ +}; + +static PFN ExtFCN[C_ARR_LEN(loadOrdinals)]; /* Labeled by ord ORD_*. */ +const Perl_PFN * const pExtFCN = ExtFCN; struct PMWIN_entries_t PMWIN_entries; HMODULE -loadModule(char *modname) +loadModule(const char *modname, int fail) { HMODULE h = (HMODULE)dlopen(modname, 0); - if (!h) + + if (!h && fail) Perl_croak_nocontext("Error loading module '%s': %s", modname, dlerror()); return h; } -APIRET -loadByOrd(char *modname, ULONG ord) +PFN +loadByOrdinal(enum entries_ordinals ord, int fail) { if (ExtFCN[ord] == NULL) { - static HMODULE hdosc = 0; - BYTE buf[20]; - PFN fcn; + PFN fcn = (PFN)-1; APIRET rc; - - if (!hdosc) { - hdosc = loadModule(modname); - if (CheckOSError(DosQueryProcAddr(hdosc, loadOrd[ord], NULL, &fcn))) - Perl_croak_nocontext( - "This version of OS/2 does not support %s.%i", - modname, loadOrd[ord]); + if (!loadOrdinals[ord].dll->handle) + loadOrdinals[ord].dll->handle + = loadModule(loadOrdinals[ord].dll->modname, fail); + if (!loadOrdinals[ord].dll->handle) + return 0; /* Possible with FAIL==0 only */ + if (CheckOSError(DosQueryProcAddr(loadOrdinals[ord].dll->handle, + loadOrdinals[ord].entrypoint, + loadOrdinals[ord].entryname,&fcn))) { + char buf[20], *s = (char*)loadOrdinals[ord].entryname; + + if (!fail) + return 0; + if (!s) + sprintf(s = buf, "%d", loadOrdinals[ord].entrypoint); + Perl_croak_nocontext( + "This version of OS/2 does not support %s.%s", + loadOrdinals[ord].dll->modname, s); } ExtFCN[ord] = fcn; } - if ((long)ExtFCN[ord] == -1) + if ((long)ExtFCN[ord] == -1) Perl_croak_nocontext("panic queryaddr"); + return ExtFCN[ord]; } void init_PMWIN_entries(void) { - static HMODULE hpmwin = 0; - static const int ords[] = { - 763, /* Initialize */ - 716, /* CreateMsgQueue */ - 726, /* DestroyMsgQueue */ - 918, /* PeekMsg */ - 915, /* GetMsg */ - 912, /* DispatchMsg */ - 753, /* GetLastError */ - 705, /* CancelShutdown */ - }; - BYTE buf[20]; - int i = 0; - unsigned long rc; - - if (hpmwin) - return; + int i; - hpmwin = loadModule("pmwin"); - while (i < sizeof(ords)/sizeof(int)) { - if (CheckOSError(DosQueryProcAddr(hpmwin, ords[i], NULL, - ((PFN*)&PMWIN_entries)+i))) - Perl_croak_nocontext("This version of OS/2 does not support pmwin.%d", ords[i]); - i++; - } + for (i = ORD_WinInitialize; i <= ORD_WinCancelShutdown; i++) + ((PFN*)&PMWIN_entries)[i - ORD_WinInitialize] = loadByOrdinal(i, 1); } +/*****************************************************/ +/* socket forwarders without linking with tcpip DLLs */ + +DeclFuncByORD(struct hostent *, gethostent, ORD_GETHOSTENT, (void), ()) +DeclFuncByORD(struct netent *, getnetent, ORD_GETNETENT, (void), ()) +DeclFuncByORD(struct protoent *, getprotoent, ORD_GETPROTOENT, (void), ()) +DeclFuncByORD(struct servent *, getservent, ORD_GETSERVENT, (void), ()) + +DeclVoidFuncByORD(sethostent, ORD_SETHOSTENT, (int x), (x)) +DeclVoidFuncByORD(setnetent, ORD_SETNETENT, (int x), (x)) +DeclVoidFuncByORD(setprotoent, ORD_SETPROTOENT, (int x), (x)) +DeclVoidFuncByORD(setservent, ORD_SETSERVENT, (int x), (x)) + +DeclVoidFuncByORD(endhostent, ORD_ENDHOSTENT, (void), ()) +DeclVoidFuncByORD(endnetent, ORD_ENDNETENT, (void), ()) +DeclVoidFuncByORD(endprotoent, ORD_ENDPROTOENT, (void), ()) +DeclVoidFuncByORD(endservent, ORD_ENDSERVENT, (void), ()) /* priorities */ static signed char priors[] = {0, 1, 3, 2}; /* Last two interchanged, self inverse. */ #define QSS_INI_BUFFER 1024 +ULONG (*pDosVerifyPidTid) (PID pid, TID tid); +static int pidtid_lookup; + PQTOPLEVEL get_sysinfo(ULONG pid, ULONG flags) { char *pbuffer; ULONG rc, buf_len = QSS_INI_BUFFER; + PQTOPLEVEL psi; + if (!pidtid_lookup) { + pidtid_lookup = 1; + *(PFN*)&pDosVerifyPidTid = loadByOrdinal(ORD_DosVerifyPidTid, 0); + } + if (pDosVerifyPidTid) { /* Warp3 or later */ + /* Up to some fixpak QuerySysState() kills the system if a non-existent + pid is used. */ + if (CheckOSError(pDosVerifyPidTid(pid, 1))) + return 0; + } New(1322, pbuffer, buf_len, char); /* QSS_PROCESS | QSS_MODULE | QSS_SEMAPHORES | QSS_SHARED */ rc = QuerySysState(flags, pid, pbuffer, buf_len); @@ -275,7 +408,12 @@ get_sysinfo(ULONG pid, ULONG flags) Safefree(pbuffer); return 0; } - return (PQTOPLEVEL)pbuffer; + psi = (PQTOPLEVEL)pbuffer; + if (psi && pid && pid != psi->procdata->pid) { + Safefree(psi); + Perl_croak_nocontext("panic: wrong pid in sysinfo"); + } + return psi; } #define PRIO_ERR 0x1111 @@ -286,14 +424,11 @@ sys_prio(pid) ULONG prio; PQTOPLEVEL psi; + if (!pid) + return PRIO_ERR; psi = get_sysinfo(pid, QSS_PROCESS); - if (!psi) { + if (!psi) return PRIO_ERR; - } - if (pid != psi->procdata->pid) { - Safefree(psi); - Perl_croak_nocontext("panic: wrong pid in sysinfo"); - } prio = psi->procdata->threads->priority; Safefree(psi); return prio; @@ -302,10 +437,7 @@ sys_prio(pid) int setpriority(int which, int pid, int val) { - ULONG rc, prio; - PQTOPLEVEL psi; - - prio = sys_prio(pid); + ULONG rc, prio = sys_prio(pid); if (!(_emx_env & 0x200)) return 0; /* Nop if not OS/2. */ if (priors[(32 - val) >> 5] + 1 == (prio >> 8)) { @@ -334,37 +466,27 @@ setpriority(int which, int pid, int val) abs(pid))) ? -1 : 0; } -/* else return CheckOSError(DosSetPriority((pid < 0) */ -/* ? PRTYS_PROCESSTREE : PRTYS_PROCESS, */ -/* priors[(32 - val) >> 5] + 1, */ -/* (32 - val) % 32 - (prio & 0xFF), */ -/* abs(pid))) */ -/* ? -1 : 0; */ } int getpriority(int which /* ignored */, int pid) { - TIB *tib; - PIB *pib; - ULONG rc, ret; + ULONG ret; if (!(_emx_env & 0x200)) return 0; /* Nop if not OS/2. */ - /* DosGetInfoBlocks has old priority! */ -/* if (CheckOSError(DosGetInfoBlocks(&tib, &pib))) return -1; */ -/* if (pid != pib->pib_ulpid) { */ ret = sys_prio(pid); if (ret == PRIO_ERR) { return -1; } -/* } else */ -/* ret = tib->tib_ptib2->tib2_ulpri; */ return (1 - priors[((ret >> 8) - 1)])*32 - (ret & 0xFF); } /*****************************************************************************/ /* spawn */ +int emx_runtime_init; /* If 1, we need to manually init it */ +int emx_exception_init; /* If 1, we need to manually set it */ + /* There is no big sense to make it thread-specific, since signals are delivered to thread 1 only. XXXX Maybe make it into an array? */ static int spawn_pid; @@ -427,11 +549,14 @@ result(pTHX_ int flag, int pid) #endif } -#define EXECF_SPAWN 0 -#define EXECF_EXEC 1 -#define EXECF_TRUEEXEC 2 -#define EXECF_SPAWN_NOWAIT 3 -#define EXECF_SPAWN_BYFLAG 4 +enum execf_t { + EXECF_SPAWN, + EXECF_EXEC, + EXECF_TRUEEXEC, + EXECF_SPAWN_NOWAIT, + EXECF_SPAWN_BYFLAG, + EXECF_SYNC +}; /* const char* const ptypes[] = { "FS", "DOS", "VIO", "PM", "DETACH" }; */ @@ -478,21 +603,28 @@ static ULONG os2_mytype; /* Spawn/exec a program, revert to shell if needed. */ /* global PL_Argv[] contains arguments. */ +extern ULONG _emx_exception ( EXCEPTIONREPORTRECORD *, + EXCEPTIONREGISTRATIONRECORD *, + CONTEXTRECORD *, + void *); + int do_spawn_ve(pTHX_ SV *really, U32 flag, U32 execf, char *inicmd, U32 addflag) { int trueflag = flag; int rc, pass = 1; char *tmps; - char buf[256], *s = 0, scrbuf[280]; char *args[4]; static char * fargs[4] = { "/bin/sh", "-c", "\"$@\"", "spawn-via-shell", }; char **argsp = fargs; - char nargs = 4; + int nargs = 4; int force_shell; - int new_stderr = -1, nostderr = 0, fl_stderr; + int new_stderr = -1, nostderr = 0; + int fl_stderr = 0; STRLEN n_a; + char *buf; + PerlIO *file; if (flag == P_WAIT) flag = P_NOWAIT; @@ -501,14 +633,14 @@ do_spawn_ve(pTHX_ SV *really, U32 flag, U32 execf, char *inicmd, U32 addflag) if (strEQ(PL_Argv[0],"/bin/sh")) PL_Argv[0] = PL_sh_path; - if (PL_Argv[0][0] != '/' && PL_Argv[0][0] != '\\' - && !(PL_Argv[0][0] && PL_Argv[0][1] == ':' - && (PL_Argv[0][2] == '/' || PL_Argv[0][2] != '\\')) - ) /* will spawnvp use PATH? */ - TAINT_ENV(); /* testing IFS here is overkill, probably */ /* We should check PERL_SH* and PERLLIB_* as well? */ if (!really || !*(tmps = SvPV(really, n_a))) tmps = PL_Argv[0]; + if (tmps[0] != '/' && tmps[0] != '\\' + && !(tmps[0] && tmps[1] == ':' + && (tmps[2] == '/' || tmps[2] != '\\')) + ) /* will spawnvp use PATH? */ + TAINT_ENV(); /* testing IFS here is overkill, probably */ reread: force_shell = 0; @@ -550,7 +682,7 @@ do_spawn_ve(pTHX_ SV *really, U32 flag, U32 execf, char *inicmd, U32 addflag) if (flag == P_NOWAIT) flag = P_PM; else if ((flag & 7) != P_PM && (flag & 7) != P_SESSION) - Perl_warner(aTHX_ WARN_EXEC, "Starting PM process with flag=%d, mytype=%d", + Perl_warner(aTHX_ packWARN(WARN_EXEC), "Starting PM process with flag=%d, mytype=%d", flag, os2_mytype); } } @@ -561,7 +693,7 @@ do_spawn_ve(pTHX_ SV *really, U32 flag, U32 execf, char *inicmd, U32 addflag) if (flag == P_NOWAIT) flag = P_SESSION; else if ((flag & 7) != P_SESSION) - Perl_warner(aTHX_ WARN_EXEC, "Starting Full Screen process with flag=%d, mytype=%d", + Perl_warner(aTHX_ packWARN(WARN_EXEC), "Starting Full Screen process with flag=%d, mytype=%d", flag, os2_mytype); } } @@ -569,6 +701,8 @@ do_spawn_ve(pTHX_ SV *really, U32 flag, U32 execf, char *inicmd, U32 addflag) case FAPPTYP_NOTSPEC: /* Let the shell handle this... */ force_shell = 1; + buf = ""; /* Pacify a warning */ + file = 0; /* Pacify a warning */ goto doshell_args; break; } @@ -601,6 +735,8 @@ do_spawn_ve(pTHX_ SV *really, U32 flag, U32 execf, char *inicmd, U32 addflag) rc = spawnvp(trueflag | P_OVERLAY,tmps,PL_Argv); else if (execf == EXECF_SPAWN_NOWAIT) rc = spawnvp(flag,tmps,PL_Argv); + else if (execf == EXECF_SYNC) + rc = spawnvp(trueflag,tmps,PL_Argv); else /* EXECF_SPAWN, EXECF_SPAWN_BYFLAG */ rc = result(aTHX_ trueflag, spawnvp(flag,tmps,PL_Argv)); @@ -618,54 +754,45 @@ do_spawn_ve(pTHX_ SV *really, U32 flag, U32 execf, char *inicmd, U32 addflag) char *scr = find_script(PL_Argv[0], TRUE, NULL, 0); if (scr) { - FILE *file; char *s = 0, *s1; - int l; + SV *scrsv = sv_2mortal(newSVpv(scr, 0)); + SV *bufsv = sv_newmortal(); - l = strlen(scr); - - if (l >= sizeof scrbuf) { - Safefree(scr); - longbuf: - Perl_warner(aTHX_ WARN_EXEC, "Size of scriptname too big: %d", l); - rc = -1; - goto finish; - } - strcpy(scrbuf, scr); Safefree(scr); - scr = scrbuf; + scr = SvPV(scrsv, n_a); /* free()ed later */ - file = fopen(scr, "r"); + file = PerlIO_open(scr, "r"); PL_Argv[0] = scr; if (!file) goto panic_file; - if (!fgets(buf, sizeof buf, file)) { /* Empty... */ - buf[0] = 0; - fclose(file); + buf = sv_gets(bufsv, file, 0 /* No append */); + if (!buf) + buf = ""; /* XXX Needed? */ + if (!buf[0]) { /* Empty... */ + PerlIO_close(file); /* Special case: maybe from -Zexe build, so there is an executable around (contrary to documentation, DosQueryAppType sometimes (?) does not append ".exe", so we could have reached this place). */ - if (l + 5 < sizeof scrbuf) { - strcpy(scrbuf + l, ".exe"); - if (PerlLIO_stat(scrbuf,&PL_statbuf) >= 0 - && !S_ISDIR(PL_statbuf.st_mode)) { - /* Found */ + sv_catpv(scrsv, ".exe"); + scr = SvPV(scrsv, n_a); /* Reload */ + if (PerlLIO_stat(scr,&PL_statbuf) >= 0 + && !S_ISDIR(PL_statbuf.st_mode)) { /* Found */ tmps = scr; pass++; goto reread; - } else - scrbuf[l] = 0; - } else - goto longbuf; + } else { /* Restore */ + SvCUR_set(scrsv, SvCUR(scrsv) - 4); + *SvEND(scrsv) = 0; + } } - if (fclose(file) != 0) { /* Failure */ + if (PerlIO_close(file) != 0) { /* Failure */ panic_file: - Perl_warner(aTHX_ WARN_EXEC, "Error reading \"%s\": %s", + Perl_warner(aTHX_ packWARN(WARN_EXEC), "Error reading \"%s\": %s", scr, Strerror(errno)); - buf[0] = 0; /* Not #! */ + buf = ""; /* Not #! */ goto doshell_args; } if (buf[0] == '#') { @@ -681,7 +808,7 @@ do_spawn_ve(pTHX_ SV *really, U32 flag, U32 execf, char *inicmd, U32 addflag) s = buf + 8; } if (!s) { - buf[0] = 0; /* Not #! */ + buf = ""; /* Not #! */ goto doshell_args; } @@ -707,11 +834,12 @@ do_spawn_ve(pTHX_ SV *really, U32 flag, U32 execf, char *inicmd, U32 addflag) *s++ = 0; } if (nargs == -1) { - Perl_warner(aTHX_ WARN_EXEC, "Too many args on %.*s line of \"%s\"", + Perl_warner(aTHX_ packWARN(WARN_EXEC), "Too many args on %.*s line of \"%s\"", s1 - buf, buf, scr); nargs = 4; argsp = fargs; } + /* Can jump from far, buf/file invalid if force_shell: */ doshell_args: { char **a = PL_Argv; @@ -733,7 +861,7 @@ do_spawn_ve(pTHX_ SV *really, U32 flag, U32 execf, char *inicmd, U32 addflag) if (inicmd) { /* No spaces at start! */ s = inicmd; while (*s && !isSPACE(*s)) { - if (*s++ = '/') { + if (*s++ == '/') { inicmd = NULL; /* Cannot use */ break; } @@ -809,7 +937,7 @@ do_spawn_ve(pTHX_ SV *really, U32 flag, U32 execf, char *inicmd, U32 addflag) } } if (rc < 0 && ckWARN(WARN_EXEC)) - Perl_warner(aTHX_ WARN_EXEC, "Can't %s \"%s\": %s\n", + Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't %s \"%s\": %s\n", ((execf != EXECF_EXEC && execf != EXECF_TRUEEXEC) ? "spawn" : "exec"), PL_Argv[0], Strerror(errno)); @@ -833,10 +961,8 @@ do_spawn3(pTHX_ char *cmd, int execf, int flag) { register char **a; register char *s; - char flags[10]; char *shell, *copt, *news = NULL; - int rc, err, seenspace = 0, mergestderr = 0; - char fullcmd[MAXNAMLEN + 1]; + int rc, seenspace = 0, mergestderr = 0; #ifdef TRYSHELL if ((shell = getenv("EMXSHELL")) != NULL) @@ -905,7 +1031,7 @@ do_spawn3(pTHX_ char *cmd, int execf, int flag) should be smart enough to start itself gloriously. */ doshell: if (execf == EXECF_TRUEEXEC) - rc = execl(shell,shell,copt,cmd,(char*)0); + rc = execl(shell,shell,copt,cmd,(char*)0); else if (execf == EXECF_EXEC) rc = spawnl(P_OVERLAY,shell,shell,copt,cmd,(char*)0); else if (execf == EXECF_SPAWN_NOWAIT) @@ -914,10 +1040,13 @@ do_spawn3(pTHX_ char *cmd, int execf, int flag) rc = spawnl(flag,shell,shell,copt,cmd,(char*)0); else { /* In the ak code internal P_NOWAIT is P_WAIT ??? */ - rc = result(aTHX_ P_WAIT, - spawnl(P_NOWAIT,shell,shell,copt,cmd,(char*)0)); + if (execf == EXECF_SYNC) + rc = spawnl(P_WAIT,shell,shell,copt,cmd,(char*)0); + else + rc = result(aTHX_ P_WAIT, + spawnl(P_NOWAIT,shell,shell,copt,cmd,(char*)0)); if (rc < 0 && ckWARN(WARN_EXEC)) - Perl_warner(aTHX_ WARN_EXEC, "Can't %s \"%s\": %s", + Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't %s \"%s\": %s", (execf == EXECF_SPAWN ? "spawn" : "exec"), shell, Strerror(errno)); if (rc < 0) @@ -956,8 +1085,10 @@ do_spawn3(pTHX_ char *cmd, int execf, int flag) /* Array spawn. */ int -os2_do_aspawn(pTHX_ SV *really, register SV **mark, register SV **sp) +os2_do_aspawn(pTHX_ SV *really, register void **vmark, register void **vsp) { + register SV **mark = (SV **)vmark; + register SV **sp = (SV **)vsp; register char **a; int rc; int flag = P_WAIT, flag_set = 0; @@ -1021,13 +1152,11 @@ PerlIO * my_syspopen(pTHX_ char *cmd, char *mode) { #ifndef USE_POPEN - int p[2]; register I32 this, that, newfd; - register I32 pid, rc; - PerlIO *res; + register I32 pid; SV *sv; - int fh_fl; + int fh_fl = 0; /* Pacify the warning */ /* `this' is what we use in the parent, `that' in the child. */ this = (*mode == 'w'); @@ -1138,51 +1267,6 @@ char * ctermid(char *s) { return 0; } void * ttyname(x) { return 0; } #endif -/******************************************************************/ -/* my socket forwarders - EMX lib only provides static forwarders */ - -static HMODULE htcp = 0; - -static void * -tcp0(char *name) -{ - PFN fcn; - - if (!(_emx_env & 0x200)) Perl_croak_nocontext("%s requires OS/2", name); /* Die if not OS/2. */ - if (!htcp) - htcp = loadModule("tcp32dll"); - if (htcp && DosQueryProcAddr(htcp, 0, name, &fcn) == 0) - return (void *) ((void * (*)(void)) fcn) (); - return 0; -} - -static void -tcp1(char *name, int arg) -{ - static BYTE buf[20]; - PFN fcn; - - if (!(_emx_env & 0x200)) Perl_croak_nocontext("%s requires OS/2", name); /* Die if not OS/2. */ - if (!htcp) - DosLoadModule(buf, sizeof buf, "tcp32dll", &htcp); - if (htcp && DosQueryProcAddr(htcp, 0, name, &fcn) == 0) - ((void (*)(int)) fcn) (arg); -} - -struct hostent * gethostent() { return tcp0("GETHOSTENT"); } -struct netent * getnetent() { return tcp0("GETNETENT"); } -struct protoent * getprotoent() { return tcp0("GETPROTOENT"); } -struct servent * getservent() { return tcp0("GETSERVENT"); } - -void sethostent(x) { tcp1("SETHOSTENT", x); } -void setnetent(x) { tcp1("SETNETENT", x); } -void setprotoent(x) { tcp1("SETPROTOENT", x); } -void setservent(x) { tcp1("SETSERVENT", x); } -void endhostent() { tcp0("ENDHOSTENT"); } -void endnetent() { tcp0("ENDNETENT"); } -void endprotoent() { tcp0("ENDPROTOENT"); } -void endservent() { tcp0("ENDSERVENT"); } - /*****************************************************************************/ /* not implemented in C Set++ */ @@ -1200,7 +1284,7 @@ int setgid(x) { errno = EINVAL; return -1; } used with 5.001. Now just look for /dev/. */ int -os2_stat(char *name, struct stat *st) +os2_stat(const char *name, struct stat *st) { static int ino = SHRT_MAX; @@ -1284,7 +1368,9 @@ XS(XS_File__Copy_syscopy) XSRETURN(1); } +#define PERL_PATCHLEVEL_H_IMPLICIT /* Do not init local_patches. */ #include "patchlevel.h" +#undef PERL_PATCHLEVEL_H_IMPLICIT char * mod2fname(pTHX_ SV *sv) @@ -1292,8 +1378,6 @@ mod2fname(pTHX_ SV *sv) static char fname[9]; int pos = 6, len, avlen; unsigned int sum = 0; - AV *av; - SV *svp; char *s; STRLEN n_a; @@ -1322,10 +1406,21 @@ mod2fname(pTHX_ SV *sv) } avlen --; } -#ifdef USE_THREADS +#ifdef USE_5005THREADS sum++; /* Avoid conflict of DLLs in memory. */ #endif - sum += PERL_VERSION * 200 + PERL_SUBVERSION * 2; /* */ + /* We always load modules as *specific* DLLs, and with the full name. + When loading a specific DLL by its full name, one cannot get a + different DLL, even if a DLL with the same basename is loaded already. + Thus there is no need to include the version into the mangling scheme. */ +#if 0 + sum += PERL_VERSION * 200 + PERL_SUBVERSION * 2; /* Up to 5.6.1 */ +#else +# ifndef COMPATIBLE_VERSION_SUM /* Binary compatibility with the 5.00553 binary */ +# define COMPATIBLE_VERSION_SUM (5 * 200 + 53 * 2) +# endif + sum += COMPATIBLE_VERSION_SUM; +#endif fname[pos] = 'A' + (sum % 26); fname[pos + 1] = 'A' + (sum / 26 % 26); fname[pos + 2] = '\0'; @@ -1353,24 +1448,54 @@ os2error(int rc) { static char buf[300]; ULONG len; + char *s; + int number = SvTRUE(get_sv("OS2::nsyserror", TRUE)); if (!(_emx_env & 0x200)) return ""; /* Nop if not OS/2. */ if (rc == 0) - return NULL; - if (DosGetMessage(NULL, 0, buf, sizeof buf - 1, rc, "OSO001.MSG", &len)) - sprintf(buf, "OS/2 system error code %d=0x%x", rc, rc); - else { - buf[len] = '\0'; - if (len && buf[len - 1] == '\n') - buf[--len] = 0; - if (len && buf[len - 1] == '\r') - buf[--len] = 0; - if (len && buf[len - 1] == '.') - buf[--len] = 0; + return ""; + if (number) { + sprintf(buf, "SYS%04d=%#x: ", rc, rc); + s = buf + strlen(buf); + } else + s = buf; + if (DosGetMessage(NULL, 0, s, sizeof(buf) - 1 - (s-buf), + rc, "OSO001.MSG", &len)) { + if (!number) { + sprintf(buf, "SYS%04d=%#x: ", rc, rc); + s = buf + strlen(buf); + } + sprintf(s, "[No description found in OSO001.MSG]"); + } else { + s[len] = '\0'; + if (len && s[len - 1] == '\n') + s[--len] = 0; + if (len && s[len - 1] == '\r') + s[--len] = 0; + if (len && s[len - 1] == '.') + s[--len] = 0; + if (len >= 10 && number && strnEQ(s, buf, 7) + && s[7] == ':' && s[8] == ' ') + /* Some messages start with SYSdddd:, some not */ + Move(s + 9, s, (len -= 9) + 1, char); } return buf; } +void +ResetWinError(void) +{ + WinError_2_Perl_rc; +} + +void +CroakWinError(int die, char *name) +{ + FillWinError; + if (die && Perl_rc) + croak("%s: %s", (name ? name : "Win* API call"), os2error(Perl_rc)); +} + char * os2_execname(pTHX) { @@ -1465,8 +1590,9 @@ Perl_Register_MQ(int serve) PPIB pib; PTIB tib; - if (Perl_os2_initial_mode++) + if (Perl_hmq_refcnt > 0) return Perl_hmq; + Perl_hmq_refcnt = 0; /* Be extra safe */ DosGetInfoBlocks(&tib, &pib); Perl_os2_initial_mode = pib->pib_ultype; /* Try morphing into a PM application. */ @@ -1754,8 +1880,8 @@ XS(XS_OS2_Process_Messages) if (items == 2) { I32 cntr; SV *sv = ST(1); - int fake = SvIV(sv); /* Force SvIVX */ - + + (void)SvIV(sv); /* Force SvIVX */ if (!SvIOK(sv)) Perl_croak_nocontext("Can't upgrade count to IV"); cntr = SvIVX(sv); @@ -1881,6 +2007,9 @@ XS(XS_Cwd_sys_cwd) RETVAL = _getcwd2(p, MAXPATHLEN); ST(0) = sv_newmortal(); sv_setpv((SV*)ST(0), RETVAL); +#ifndef INCOMPLETE_TAINTS + SvTAINTED_on(ST(0)); +#endif } XSRETURN(1); } @@ -1893,9 +2022,11 @@ XS(XS_Cwd_sys_abspath) { STRLEN n_a; char * path = (char *)SvPV(ST(0),n_a); - char * dir; + char * dir, *s, *t, *e; char p[MAXPATHLEN]; char * RETVAL; + int l; + SV *sv; if (items < 2) dir = NULL; @@ -1948,8 +2079,6 @@ XS(XS_Cwd_sys_abspath) In all the cases it is safe to drop the drive part of the path. */ if ( !sys_is_relative(path) ) { - int is_drived; - if ( ( ( sys_is_absolute(dir) || (isALPHA(dir[0]) && dir[1] == ':' && strnicmp(dir, path,1) == 0)) @@ -1987,28 +2116,61 @@ XS(XS_Cwd_sys_abspath) done: } } + if (!RETVAL) + XSRETURN_EMPTY; + /* Backslashes are already converted to slashes. */ + /* Remove trailing slashes */ + l = strlen(RETVAL); + while (l > 0 && RETVAL[l-1] == '/') + l--; ST(0) = sv_newmortal(); - sv_setpv((SV*)ST(0), RETVAL); + sv_setpvn( sv = (SV*)ST(0), RETVAL, l); + /* Remove duplicate slashes, skipping the first three, which + may be parts of a server-based path */ + s = t = 3 + SvPV_force(sv, n_a); + e = SvEND(sv); + /* Do not worry about multibyte chars here, this would contradict the + eventual UTFization, and currently most other places break too... */ + while (s < e) { + if (s[0] == t[-1] && s[0] == '/') + s++; /* Skip duplicate / */ + else + *t++ = *s++; + } + if (t < e) { + *t = 0; + SvCUR_set(sv, t - SvPVX(sv)); + } } XSRETURN(1); } typedef APIRET (*PELP)(PSZ path, ULONG type); +/* Kernels after 2000/09/15 understand this too: */ +#ifndef LIBPATHSTRICT +# define LIBPATHSTRICT 3 +#endif + APIRET -ExtLIBPATH(ULONG ord, PSZ path, ULONG type) +ExtLIBPATH(ULONG ord, PSZ path, IV type) { - loadByOrd("doscalls",ord); /* Guarantied to load or die! */ - return (*(PELP)ExtFCN[ord])(path, type); + ULONG what; + PFN f = loadByOrdinal(ord, 1); /* Guarantied to load or die! */ + + if (type > 0) + what = END_LIBPATH; + else if (type == 0) + what = BEGIN_LIBPATH; + else + what = LIBPATHSTRICT; + return (*(PELP)f)(path, what); } -#define extLibpath(type) \ - (CheckOSError(ExtLIBPATH(ORD_QUERY_ELP, to, ((type) ? END_LIBPATH \ - : BEGIN_LIBPATH))) \ - ? NULL : to ) +#define extLibpath(to,type) \ + (CheckOSError(ExtLIBPATH(ORD_DosQueryExtLibpath, (to), (type))) ? NULL : (to) ) #define extLibpath_set(p,type) \ - (!CheckOSError(ExtLIBPATH(ORD_SET_ELP, (p), ((type) ? END_LIBPATH \ - : BEGIN_LIBPATH)))) + (!CheckOSError(ExtLIBPATH(ORD_DosSetExtLibpath, (p), (type)))) XS(XS_Cwd_extLibpath) { @@ -2016,7 +2178,7 @@ XS(XS_Cwd_extLibpath) if (items < 0 || items > 1) Perl_croak_nocontext("Usage: Cwd::extLibpath(type = 0)"); { - bool type; + IV type; char to[1024]; U32 rc; char * RETVAL; @@ -2024,10 +2186,13 @@ XS(XS_Cwd_extLibpath) if (items < 1) type = 0; else { - type = (int)SvIV(ST(0)); + type = SvIV(ST(0)); } - RETVAL = extLibpath(type); + to[0] = 1; to[1] = 0; /* Sometimes no error reported */ + RETVAL = extLibpath(to, type); + if (RETVAL && RETVAL[0] == 1 && RETVAL[1] == 0) + Perl_croak_nocontext("panic Cwd::extLibpath parameter"); ST(0) = sv_newmortal(); sv_setpv((SV*)ST(0), RETVAL); } @@ -2042,14 +2207,14 @@ XS(XS_Cwd_extLibpath_set) { STRLEN n_a; char * s = (char *)SvPV(ST(0),n_a); - bool type; + IV type; U32 rc; bool RETVAL; if (items < 2) type = 0; else { - type = (int)SvIV(ST(1)); + type = SvIV(ST(1)); } RETVAL = extLibpath_set(s, type); @@ -2059,6 +2224,78 @@ XS(XS_Cwd_extLibpath_set) XSRETURN(1); } +/* Input: Address, BufLen +APIRET APIENTRY +DosQueryModFromEIP (HMODULE * hmod, ULONG * obj, ULONG BufLen, PCHAR Buf, + ULONG * Offset, ULONG Address); +*/ + +DeclOSFuncByORD(APIRET, _DosQueryModFromEIP,ORD_DosQueryModFromEIP, + (HMODULE * hmod, ULONG * obj, ULONG BufLen, PCHAR Buf, + ULONG * Offset, ULONG Address), + (hmod, obj, BufLen, Buf, Offset, Address)) + +enum module_name_how { mod_name_handle, mod_name_shortname, mod_name_full}; + +static SV* +module_name_at(void *pp, enum module_name_how how) +{ + char buf[MAXPATHLEN]; + char *p = buf; + HMODULE mod; + ULONG obj, offset, rc; + + if (!_DosQueryModFromEIP(&mod, &obj, sizeof(buf), buf, &offset, (ULONG)pp)) + return &PL_sv_undef; + if (how == mod_name_handle) + return newSVuv(mod); + /* Full name... */ + if ( how == mod_name_full + && CheckOSError(DosQueryModuleName(mod, sizeof(buf), buf)) ) + return &PL_sv_undef; + while (*p) { + if (*p == '\\') + *p = '/'; + p++; + } + return newSVpv(buf, 0); +} + +static SV* +module_name_of_cv(SV *cv, enum module_name_how how) +{ + if (!cv || !SvROK(cv) || SvTYPE(SvRV(cv)) != SVt_PVCV || !CvXSUB(SvRV(cv))) + croak("Not an XSUB reference"); + return module_name_at(CvXSUB(SvRV(cv)), how); +} + +/* Find module name to which *this* subroutine is compiled */ +#define module_name(how) module_name_at(&module_name_at, how) + +XS(XS_OS2_DLLname) +{ + dXSARGS; + if (items > 2) + Perl_croak(aTHX_ "Usage: OS2::DLLname( [ how, [\\&xsub] ] )"); + { + SV * RETVAL; + int how; + + if (items < 1) + how = mod_name_full; + else { + how = (int)SvIV(ST(0)); + } + if (items < 2) + RETVAL = module_name(how); + else + RETVAL = module_name_of_cv(ST(1), how); + ST(0) = RETVAL; + sv_2mortal(ST(0)); + } + XSRETURN(1); +} + #define get_control87() _control87(0,0) #define set_control87 _control87 @@ -2156,11 +2393,15 @@ Xs_OS2_init(pTHX) newXSproto("OS2::_control87", XS_OS2__control87, file, "$$"); newXSproto("OS2::get_control87", XS_OS2_get_control87, file, ""); newXSproto("OS2::set_control87", XS_OS2_set_control87, file, ";$$"); + newXSproto("OS2::DLLname", XS_OS2_DLLname, file, ";$$"); gv = gv_fetchpv("OS2::is_aout", TRUE, SVt_PV); GvMULTI_on(gv); #ifdef PERL_IS_AOUT sv_setiv(GvSV(gv), 1); -#endif +#endif + gv = gv_fetchpv("OS2::can_fork", TRUE, SVt_PV); + GvMULTI_on(gv); + sv_setiv(GvSV(gv), exe_is_aout()); gv = gv_fetchpv("OS2::emx_rev", TRUE, SVt_PV); GvMULTI_on(gv); sv_setiv(GvSV(gv), _emx_rev); @@ -2172,23 +2413,334 @@ Xs_OS2_init(pTHX) gv = gv_fetchpv("OS2::os_ver", TRUE, SVt_PV); GvMULTI_on(gv); sv_setnv(GvSV(gv), _osmajor + 0.001 * _osminor); + gv = gv_fetchpv("OS2::nsyserror", TRUE, SVt_PV); + GvMULTI_on(gv); + sv_setiv(GvSV(gv), 1); /* DEFAULT: Show number on syserror */ } + return 0; } OS2_Perl_data_t OS2_Perl_data; +extern void _emx_init(void*); + +static void jmp_out_of_atexit(void); + +#define FORCE_EMX_INIT_CONTRACT_ARGV 1 +#define FORCE_EMX_INIT_INSTALL_ATEXIT 2 + +static void +my_emx_init(void *layout) { + static volatile void *p = 0; /* Cannot be on stack! */ + + /* Can't just call emx_init(), since it moves the stack pointer */ + /* It also busts a lot of registers, so be extra careful */ + __asm__( "pushf\n" + "pusha\n" + "movl %%esp, %1\n" + "push %0\n" + "call __emx_init\n" + "movl %1, %%esp\n" + "popa\n" + "popf\n" : : "r" (layout), "m" (p) ); +} + +struct layout_table_t { + ULONG text_base; + ULONG text_end; + ULONG data_base; + ULONG data_end; + ULONG bss_base; + ULONG bss_end; + ULONG heap_base; + ULONG heap_end; + ULONG heap_brk; + ULONG heap_off; + ULONG os2_dll; + ULONG stack_base; + ULONG stack_end; + ULONG flags; + ULONG reserved[2]; + char options[64]; +}; + +static ULONG +my_os_version() { + static ULONG res; /* Cannot be on stack! */ + + /* Can't just call __os_version(), since it does not follow C + calling convention: it busts a lot of registers, so be extra careful */ + __asm__( "pushf\n" + "pusha\n" + "call ___os_version\n" + "movl %%eax, %0\n" + "popa\n" + "popf\n" : "=m" (res) ); + + return res; +} + +static void +force_init_emx_runtime(EXCEPTIONREGISTRATIONRECORD *preg, ULONG flags) +{ + /* Calling emx_init() will bust the top of stack: it installs an + exception handler and puts argv data there. */ + char *oldarg, *oldenv; + void *oldstackend, *oldstack; + PPIB pib; + PTIB tib; + static ULONG os2_dll; + ULONG rc, error = 0, out; + char buf[512]; + static struct layout_table_t layout_table; + struct { + char buf[48*1024]; /* _emx_init() requires 32K, cmd.exe has 64K only */ + double alignment1; + EXCEPTIONREGISTRATIONRECORD xreg; + } *newstack; + char *s; + + layout_table.os2_dll = (ULONG)&os2_dll; + layout_table.flags = 0x02000002; /* flags: application, OMF */ + + DosGetInfoBlocks(&tib, &pib); + oldarg = pib->pib_pchcmd; + oldenv = pib->pib_pchenv; + oldstack = tib->tib_pstack; + oldstackend = tib->tib_pstacklimit; + + /* Minimize the damage to the stack via reducing the size of argv. */ + if (flags & FORCE_EMX_INIT_CONTRACT_ARGV) { + pib->pib_pchcmd = "\0\0"; /* Need 3 concatenated strings */ + pib->pib_pchcmd = "\0"; /* Ended by an extra \0. */ + } + + newstack = alloca(sizeof(*newstack)); + /* Emulate the stack probe */ + s = ((char*)newstack) + sizeof(*newstack); + while (s > (char*)newstack) { + s[-1] = 0; + s -= 4096; + } + + /* Reassigning stack is documented to work */ + tib->tib_pstack = (void*)newstack; + tib->tib_pstacklimit = (void*)((char*)newstack + sizeof(*newstack)); + + /* Can't just call emx_init(), since it moves the stack pointer */ + my_emx_init((void*)&layout_table); + + /* Remove the exception handler, cannot use it - too low on the stack. + Check whether it is inside the new stack. */ + buf[0] = 0; + if (tib->tib_pexchain >= tib->tib_pstacklimit + || tib->tib_pexchain < tib->tib_pstack) { + error = 1; + sprintf(buf, + "panic: ExceptionHandler misplaced: not %#lx <= %#lx < %#lx\n", + (unsigned long)tib->tib_pstack, + (unsigned long)tib->tib_pexchain, + (unsigned long)tib->tib_pstacklimit); + goto finish; + } + if (tib->tib_pexchain != &(newstack->xreg)) { + sprintf(buf, "ExceptionHandler misplaced: %#lx != %#lx\n", + (unsigned long)tib->tib_pexchain, + (unsigned long)&(newstack->xreg)); + } + rc = DosUnsetExceptionHandler((EXCEPTIONREGISTRATIONRECORD *)tib->tib_pexchain); + if (rc) + sprintf(buf + strlen(buf), + "warning: DosUnsetExceptionHandler rc=%#lx=%lu\n", rc, rc); + + if (preg) { + /* ExceptionRecords should be on stack, in a correct order. Sigh... */ + preg->prev_structure = 0; + preg->ExceptionHandler = _emx_exception; + rc = DosSetExceptionHandler(preg); + if (rc) { + sprintf(buf + strlen(buf), + "warning: DosSetExceptionHandler rc=%#lx=%lu\n", rc, rc); + DosWrite(2, buf, strlen(buf), &out); + emx_exception_init = 1; /* Do it around spawn*() calls */ + } + } else + emx_exception_init = 1; /* Do it around spawn*() calls */ + + finish: + /* Restore the damage */ + pib->pib_pchcmd = oldarg; + pib->pib_pchcmd = oldenv; + tib->tib_pstacklimit = oldstackend; + tib->tib_pstack = oldstack; + emx_runtime_init = 1; + if (buf[0]) + DosWrite(2, buf, strlen(buf), &out); + if (error) + exit(56); +} + +jmp_buf at_exit_buf; +int longjmp_at_exit; + +static void +jmp_out_of_atexit(void) +{ + if (longjmp_at_exit) + longjmp(at_exit_buf, 1); +} + +extern void _CRT_term(void); + +int emx_runtime_secondary; + +void +Perl_OS2_term(void **p, int exitstatus, int flags) +{ + if (!emx_runtime_secondary) + return; + + /* The principal executable is not running the same CRTL, so there + is nobody to shutdown *this* CRTL except us... */ + if (flags & FORCE_EMX_DEINIT_EXIT) { + if (p && !emx_exception_init) + DosUnsetExceptionHandler((EXCEPTIONREGISTRATIONRECORD *)p); + /* Do not run the executable's CRTL's termination routines */ + exit(exitstatus); /* Run at-exit, flush buffers, etc */ + } + /* Run at-exit list, and jump out at the end */ + if ((flags & FORCE_EMX_DEINIT_RUN_ATEXIT) && !setjmp(at_exit_buf)) { + longjmp_at_exit = 1; + exit(exitstatus); /* The first pass through "if" */ + } + + /* Get here if we managed to jump out of exit(), or did not run atexit. */ + longjmp_at_exit = 0; /* Maybe exit() is called again? */ +#if 0 /* _atexit_n is not exported */ + if (flags & FORCE_EMX_DEINIT_RUN_ATEXIT) + _atexit_n = 0; /* Remove the atexit() handlers */ +#endif + /* Will segfault on program termination if we leave this dangling... */ + if (p && !emx_exception_init) + DosUnsetExceptionHandler((EXCEPTIONREGISTRATIONRECORD *)p); + /* Typically there is no need to do this, done from _DLL_InitTerm() */ + if (flags & FORCE_EMX_DEINIT_CRT_TERM) + _CRT_term(); /* Flush buffers, etc. */ + /* Now it is a good time to call exit() in the caller's CRTL... */ +} + +#include <emx/startup.h> + +extern ULONG __os_version(); /* See system.doc */ + +static int emx_wasnt_initialized; + +void +check_emx_runtime(char **env, EXCEPTIONREGISTRATIONRECORD *preg) +{ + ULONG v_crt, v_emx; + + /* If _environ is not set, this code sits in a DLL which + uses a CRT DLL which not compatible with the executable's + CRT library. Some parts of the DLL are not initialized. + */ + if (_environ != NULL) + return; /* Properly initialized */ + + /* If the executable does not use EMX.DLL, EMX.DLL is not completely + initialized either. Uninitialized EMX.DLL returns 0 in the low + nibble of __os_version(). */ + v_emx = my_os_version(); + + /* _osmajor and _osminor are normally set in _DLL_InitTerm of CRT DLL + (=>_CRT_init=>_entry2) via a call to __os_version(), then + reset when the EXE initialization code calls _text=>_init=>_entry2. + The first time they are wrongly set to 0; the second time the + EXE initialization code had already called emx_init=>initialize1 + which correctly set version_major, version_minor used by + __os_version(). */ + v_crt = (_osmajor | _osminor); + + if ((_emx_env & 0x200) && !(v_emx & 0xFFFF)) { /* OS/2, EMX uninit. */ + force_init_emx_runtime( preg, + FORCE_EMX_INIT_CONTRACT_ARGV + | FORCE_EMX_INIT_INSTALL_ATEXIT ); + emx_wasnt_initialized = 1; + /* Update CRTL data basing on now-valid EMX runtime data */ + if (!v_crt) { /* The only wrong data are the versions. */ + v_emx = my_os_version(); /* *Now* it works */ + *(unsigned char *)&_osmajor = v_emx & 0xFF; /* Cast out const */ + *(unsigned char *)&_osminor = (v_emx>>8) & 0xFF; + } + } + emx_runtime_secondary = 1; + /* if (flags & FORCE_EMX_INIT_INSTALL_ATEXIT) */ + atexit(jmp_out_of_atexit); /* Allow run of atexit() w/o exit() */ + + if (env == NULL) { /* Fetch from the process info block */ + int c = 0; + PPIB pib; + PTIB tib; + char *e, **ep; + + DosGetInfoBlocks(&tib, &pib); + e = pib->pib_pchenv; + while (*e) { /* Get count */ + c++; + e = e + strlen(e) + 1; + } + New(1307, env, c + 1, char*); + ep = env; + e = pib->pib_pchenv; + while (c--) { + *ep++ = e; + e = e + strlen(e) + 1; + } + *ep = NULL; + } + _environ = _org_environ = env; +} + +#define ENTRY_POINT 0x10000 + +static int +exe_is_aout(void) +{ + struct layout_table_t *layout; + if (emx_wasnt_initialized) + return 0; + /* Now we know that the principal executable is an EMX application + - unless somebody did already play with delayed initialization... */ + /* With EMX applications to determine whether it is AOUT one needs + to examine the start of the executable to find "layout" */ + if ( *(unsigned char*)ENTRY_POINT != 0x68 /* PUSH n */ + || *(unsigned char*)(ENTRY_POINT+5) != 0xe8 /* CALL */ + || *(unsigned char*)(ENTRY_POINT+10) != 0xeb /* JMP */ + || *(unsigned char*)(ENTRY_POINT+12) != 0xe8) /* CALL */ + return 0; /* ! EMX executable */ + /* Fix alignment */ + Copy((char*)(ENTRY_POINT+1), &layout, 1, struct layout_table_t*); + return !(layout->flags & 2); +} + void Perl_OS2_init(char **env) { + Perl_OS2_init3(env, 0, 0); +} + +void +Perl_OS2_init3(char **env, void **preg, int flags) +{ char *shell; + _uflags (_UF_SBRK_MODEL, _UF_SBRK_ARBITRARY); MALLOC_INIT; + + check_emx_runtime(env, (EXCEPTIONREGISTRATIONRECORD *)preg); + settmppath(); OS2_Perl_data.xs_init = &Xs_OS2_init; - _uflags (_UF_SBRK_MODEL, _UF_SBRK_ARBITRARY); - if (environ == NULL && env) { - environ = env; - } if ( (shell = getenv("PERL_SH_DRIVE")) ) { New(1304, PL_sh_path, strlen(SH_PATH) + 1, char); strcpy(PL_sh_path, SH_PATH); @@ -2218,7 +2770,6 @@ char * my_tmpnam (char *str) { char *p = getenv("TMP"), *tpath; - int len; if (!p) p = getenv("TEMP"); tpath = tempnam(p, "pltmp"); @@ -2296,21 +2847,21 @@ my_flock(int handle, int o) if (!(_emx_env & 0x200) || !use_my) return flock(handle, o); /* Delegate to EMX. */ - // is this a file? + /* is this a file? */ if ((DosQueryHType(handle, &handle_type, &flag_word) != 0) || (handle_type & 0xFF)) { errno = EBADF; return -1; } - // set lock/unlock ranges + /* set lock/unlock ranges */ rNull.lOffset = rNull.lRange = rFull.lOffset = 0; rFull.lRange = 0x7FFFFFFF; - // set timeout for blocking + /* set timeout for blocking */ timeout = ((blocking = !(o & LOCK_NB))) ? 100 : 1; - // shared or exclusive? + /* shared or exclusive? */ shared = (o & LOCK_SH) ? 1 : 0; - // do not block the unlock + /* do not block the unlock */ if (o & (LOCK_UN | LOCK_SH | LOCK_EX)) { rc = DosSetFileLocks(handle, &rFull, &rNull, timeout, shared); switch (rc) { @@ -2324,7 +2875,7 @@ my_flock(int handle, int o) errno = ENOLCK; return -1; case ERROR_LOCK_VIOLATION: - break; // not an error + break; /* not an error */ case ERROR_INVALID_PARAMETER: case ERROR_ATOMIC_LOCK_NOT_SUPPORTED: case ERROR_READ_LOCKS_NOT_SUPPORTED: @@ -2338,9 +2889,9 @@ my_flock(int handle, int o) return -1; } } - // lock may block + /* lock may block */ if (o & (LOCK_SH | LOCK_EX)) { - // for blocking operations + /* for blocking operations */ for (;;) { rc = DosSetFileLocks( @@ -2378,7 +2929,7 @@ my_flock(int handle, int o) errno = EINVAL; return -1; } - // give away timeslice + /* give away timeslice */ DosSleep(1); } } @@ -2386,3 +2937,114 @@ my_flock(int handle, int o) errno = 0; return 0; } + +static int pwent_cnt; +static int _my_pwent = -1; + +static int +use_my_pwent(void) +{ + if (_my_pwent == -1) { + char *s = getenv("USE_PERL_PWENT"); + if (s) + _my_pwent = atoi(s); + else + _my_pwent = 1; + } + return _my_pwent; +} + +#undef setpwent +#undef getpwent +#undef endpwent + +void +my_setpwent(void) +{ + if (!use_my_pwent()) { + setpwent(); /* Delegate to EMX. */ + return; + } + pwent_cnt = 0; +} + +void +my_endpwent(void) +{ + if (!use_my_pwent()) { + endpwent(); /* Delegate to EMX. */ + return; + } +} + +struct passwd * +my_getpwent (void) +{ + if (!use_my_pwent()) + return getpwent(); /* Delegate to EMX. */ + if (pwent_cnt++) + return 0; /* Return one entry only */ + return getpwuid(0); +} + +static int grent_cnt; + +void +setgrent(void) +{ + grent_cnt = 0; +} + +void +endgrent(void) +{ +} + +struct group * +getgrent (void) +{ + if (grent_cnt++) + return 0; /* Return one entry only */ + return getgrgid(0); +} + +#undef getpwuid +#undef getpwnam + +/* Too long to be a crypt() of anything, so it is not-a-valid pw_passwd. */ +static const char pw_p[] = "Jf0Wb/BzMFvk7K7lrzK"; + +static struct passwd * +passw_wrap(struct passwd *p) +{ + static struct passwd pw; + char *s; + + if (!p || (p->pw_passwd && *p->pw_passwd)) /* Not a dangerous password */ + return p; + pw = *p; + s = getenv("PW_PASSWD"); + if (!s) + s = (char*)pw_p; /* Make match impossible */ + + pw.pw_passwd = s; + return &pw; +} + +struct passwd * +my_getpwuid (uid_t id) +{ + return passw_wrap(getpwuid(id)); +} + +struct passwd * +my_getpwnam (__const__ char *n) +{ + return passw_wrap(getpwnam(n)); +} + +char * +gcvt_os2 (double value, int digits, char *buffer) +{ + return gcvt (value, digits, buffer); +} diff --git a/gnu/usr.bin/perl/os2/os2ish.h b/gnu/usr.bin/perl/os2/os2ish.h index 30e67ca071d..1b38b85427b 100644 --- a/gnu/usr.bin/perl/os2/os2ish.h +++ b/gnu/usr.bin/perl/os2/os2ish.h @@ -1,4 +1,6 @@ #include <signal.h> +#include <io.h> +/* #include <sys/select.h> */ /* HAS_IOCTL: * This symbol, if defined, indicates that the ioctl() routine is @@ -17,6 +19,23 @@ #define HAS_DLERROR #define HAS_WAITPID_RUNTIME (_emx_env & 0x200) +/* HAS_PASSWD + * This symbol, if defined, indicates that the getpwnam() and + * getpwuid() routines are available to get password entries. + * The getpwent() has a separate definition, HAS_GETPWENT. + */ +#define HAS_PASSWD + +/* HAS_GROUP + * This symbol, if defined, indicates that the getgrnam() and + * getgrgid() routines are available to get group entries. + * The getgrent() has a separate definition, HAS_GETGRENT. + */ +#define HAS_GROUP +#define HAS_GETGRENT /* fake */ +#define HAS_SETGRENT /* fake */ +#define HAS_ENDGRENT /* fake */ + /* USEMYBINMODE * This symbol, if defined, indicates that the program should * use the routine my_binmode(FILE *fp, char iotype, int mode) to insure @@ -80,7 +99,7 @@ # undef I_SYS_UN #endif -#ifdef USE_THREADS +#ifdef USE_5005THREADS #define do_spawn(a) os2_do_spawn(aTHX_ (a)) #define do_aspawn(a,b,c) os2_do_aspawn(aTHX_ (a),(b),(c)) @@ -183,39 +202,64 @@ int pthread_create(pthread_t *tid, const pthread_attr_t *attr, #define THREADS_ELSEWHERE -#else /* USE_THREADS */ +#else /* USE_5005THREADS */ #define do_spawn(a) os2_do_spawn(a) #define do_aspawn(a,b,c) os2_do_aspawn((a),(b),(c)) -#endif /* USE_THREADS */ +#endif /* USE_5005THREADS */ void Perl_OS2_init(char **); +void Perl_OS2_init3(char **envp, void **excH, int flags); +void Perl_OS2_term(void **excH, int exitstatus, int flags); -/* XXX This code hideously puts env inside: */ +/* The code without INIT3 hideously puts env inside: */ +/* These ones should be in the same block as PERL_SYS_TERM() */ #ifdef PERL_CORE -# define PERL_SYS_INIT3(argcp, argvp, envp) STMT_START { \ + +# define PERL_SYS_INIT3(argcp, argvp, envp) \ + { void *xreg[2]; \ _response(argcp, argvp); \ _wildcard(argcp, argvp); \ - Perl_OS2_init(*envp); } STMT_END -# define PERL_SYS_INIT(argcp, argvp) STMT_START { \ + Perl_OS2_init3(*envp, xreg, 0) + +# define PERL_SYS_INIT(argcp, argvp) { \ + { void *xreg[2]; \ _response(argcp, argvp); \ _wildcard(argcp, argvp); \ - Perl_OS2_init(NULL); } STMT_END + Perl_OS2_init3(NULL, xreg, 0) + #else /* Compiling embedded Perl or Perl extension */ -# define PERL_SYS_INIT3(argcp, argvp, envp) STMT_START { \ - Perl_OS2_init(*envp); } STMT_END -# define PERL_SYS_INIT(argcp, argvp) STMT_START { \ - Perl_OS2_init(NULL); } STMT_END + +# define PERL_SYS_INIT3(argcp, argvp, envp) \ + { void *xreg[2]; \ + Perl_OS2_init3(*envp, xreg, 0) +# define PERL_SYS_INIT(argcp, argvp) { \ + { void *xreg[2]; \ + Perl_OS2_init3(NULL, xreg, 0) #endif +#define FORCE_EMX_DEINIT_EXIT 1 +#define FORCE_EMX_DEINIT_CRT_TERM 2 +#define FORCE_EMX_DEINIT_RUN_ATEXIT 4 + +#define PERL_SYS_TERM2(xreg,flags) \ + Perl_OS2_term(xreg, 0, flags); \ + MALLOC_TERM + +#define PERL_SYS_TERM1(xreg) \ + Perl_OS2_term(xreg, 0, FORCE_EMX_DEINIT_RUN_ATEXIT) + +/* This one should come in pair with PERL_SYS_INIT() and in the same block */ +#define PERL_SYS_TERM() \ + PERL_SYS_TERM1(xreg); \ + } + #ifndef __EMX__ # define PERL_CALLCONV _System #endif -#define PERL_SYS_TERM() MALLOC_TERM - /* #define PERL_SYS_TERM() STMT_START { \ if (Perl_HAB_set) WinTerminate(Perl_hab); } STMT_END */ @@ -263,6 +307,17 @@ FILE *my_tmpfile (void); char *my_tmpnam (char *); int my_mkdir (__const__ char *, long); int my_rmdir (__const__ char *); +struct passwd *my_getpwent (void); +void my_setpwent (void); +void my_endpwent (void); +char *gcvt_os2(double value, int digits, char *buffer); + +struct group *getgrent (void); +void setgrent (void); +void endgrent (void); + +struct passwd *my_getpwuid (uid_t); +struct passwd *my_getpwnam (__const__ char *); #undef L_tmpnam #define L_tmpnam MAXPATHLEN @@ -287,6 +342,11 @@ int my_rmdir (__const__ char *); #define flock my_flock #define rmdir my_rmdir #define mkdir my_mkdir +#define setpwent my_setpwent +#define getpwent my_getpwent +#define endpwent my_endpwent +#define getpwuid my_getpwuid +#define getpwnam my_getpwnam void *emx_calloc (size_t, size_t); void emx_free (void *); @@ -297,6 +357,8 @@ void *emx_realloc (void *, size_t); #include <stdlib.h> /* before the following definitions */ #include <unistd.h> /* before the following definitions */ +#include <fcntl.h> +#include <sys/stat.h> #define chdir _chdir2 #define getcwd _getcwd2 @@ -310,6 +372,26 @@ void *emx_realloc (void *, size_t); ? (--FILE_ptr(fp), ++FILE_cnt(fp), (int)c) : ungetc(c,fp)) #endif +#define PERLIO_IS_BINMODE_FD(fd) _PERLIO_IS_BINMODE_FD(fd) + +#ifdef __GNUG__ +# define HAS_BOOL +#endif +#ifndef HAS_BOOL +# define bool char +# define HAS_BOOL 1 +#endif + +#include <emx/io.h> /* for _fd_flags() prototype */ + +static inline bool +_PERLIO_IS_BINMODE_FD(int fd) +{ + int *pflags = _fd_flags(fd); + + return pflags && (*pflags) & O_BINARY; +} + /* ctermid is missing from emx0.9d */ char *ctermid(char *s); @@ -420,25 +502,250 @@ void init_PMWIN_entries(void); /* INCL_DOSERRORS needed. rc should be declared outside. */ #define CheckOSError(expr) (!(rc = (expr)) ? 0 : (FillOSError(rc), 1)) /* INCL_WINERRORS needed. */ -#define SaveWinError(expr) ((expr) ? : (FillWinError, 0)) #define CheckWinError(expr) ((expr) ? 0: (FillWinError, 1)) + +/* This form propagates the return value, setting $^E if needed */ +#define SaveWinError(expr) ((expr) ? : (FillWinError, 0)) + +/* This form propagates the return value, dieing with $^E if needed */ +#define SaveCroakWinError(expr,die,name1,name2) \ + ((expr) ? : (CroakWinError(die,name1 name2), 0)) + #define FillOSError(rc) (os2_setsyserrno(rc), \ Perl_severity = SEVERITY_ERROR) +#define WinError_2_Perl_rc \ + ( init_PMWIN_entries(), \ + Perl_rc=(*PMWIN_entries.GetLastError)(perl_hab_GET()) ) + +/* Calling WinGetLastError() resets the error code of the current thread. + Since for some Win* API return value 0 is normal, one needs to call + this before calling them to distinguish normal and anomalous returns. */ +/*#define ResetWinError() WinError_2_Perl_rc */ + /* At this moment init_PMWIN_entries() should be a nop (WinInitialize should be called already, right?), so we do not risk stepping over our own error */ -#define FillWinError ( init_PMWIN_entries(), \ - Perl_rc=(*PMWIN_entries.GetLastError)(perl_hab_GET()),\ +#define FillWinError ( WinError_2_Perl_rc, \ Perl_severity = ERRORIDSEV(Perl_rc), \ Perl_rc = ERRORIDERROR(Perl_rc), \ os2_setsyserrno(Perl_rc)) #define STATIC_FILE_LENGTH 127 + /* This should match loadOrdinals[] array in os2.c */ +enum entries_ordinals { + ORD_DosQueryExtLibpath, + ORD_DosSetExtLibpath, + ORD_DosVerifyPidTid, + ORD_SETHOSTENT, + ORD_SETNETENT, + ORD_SETPROTOENT, + ORD_SETSERVENT, + ORD_GETHOSTENT, + ORD_GETNETENT, + ORD_GETPROTOENT, + ORD_GETSERVENT, + ORD_ENDHOSTENT, + ORD_ENDNETENT, + ORD_ENDPROTOENT, + ORD_ENDSERVENT, + ORD_WinInitialize, + ORD_WinCreateMsgQueue, + ORD_WinDestroyMsgQueue, + ORD_WinPeekMsg, + ORD_WinGetMsg, + ORD_WinDispatchMsg, + ORD_WinGetLastError, + ORD_WinCancelShutdown, + ORD_RexxStart, + ORD_RexxVariablePool, + ORD_RexxRegisterFunctionExe, + ORD_RexxDeregisterFunction, + ORD_DOSSMSETTITLE, + ORD_PRF32QUERYPROFILESIZE, + ORD_PRF32OPENPROFILE, + ORD_PRF32CLOSEPROFILE, + ORD_PRF32QUERYPROFILE, + ORD_PRF32RESET, + ORD_PRF32QUERYPROFILEDATA, + ORD_PRF32WRITEPROFILEDATA, + + ORD_WinChangeSwitchEntry, + ORD_WinQuerySwitchEntry, + ORD_WinQuerySwitchHandle, + ORD_WinQuerySwitchList, + ORD_WinSwitchToProgram, + ORD_WinBeginEnumWindows, + ORD_WinEndEnumWindows, + ORD_WinEnumDlgItem, + ORD_WinGetNextWindow, + ORD_WinIsChild, + ORD_WinQueryActiveWindow, + ORD_WinQueryClassName, + ORD_WinQueryFocus, + ORD_WinQueryWindow, + ORD_WinQueryWindowPos, + ORD_WinQueryWindowProcess, + ORD_WinQueryWindowText, + ORD_WinQueryWindowTextLength, + ORD_WinSetFocus, + ORD_WinSetWindowPos, + ORD_WinSetWindowText, + ORD_WinShowWindow, + ORD_WinIsWindow, + ORD_WinWindowFromId, + ORD_WinWindowFromPoint, + ORD_WinPostMsg, + ORD_WinEnableWindow, + ORD_WinEnableWindowUpdate, + ORD_WinIsWindowEnabled, + ORD_WinIsWindowShowing, + ORD_WinIsWindowVisible, + ORD_WinQueryWindowPtr, + ORD_WinQueryWindowULong, + ORD_WinQueryWindowUShort, + ORD_WinSetWindowBits, + ORD_WinSetWindowPtr, + ORD_WinSetWindowULong, + ORD_WinSetWindowUShort, + ORD_WinQueryDesktopWindow, + ORD_WinSetActiveWindow, + ORD_DosQueryModFromEIP, + ORD_NENTRIES +}; + +/* RET: return type, AT: argument signature in (), ARGS: should be in () */ +#define CallORD(ret,o,at,args) (((ret (*)at) loadByOrdinal(o, 1))args) +#define DeclFuncByORD(ret,name,o,at,args) \ + ret name at { return CallORD(ret,o,at,args); } +#define DeclVoidFuncByORD(name,o,at,args) \ + void name at { CallORD(void,o,at,args); } + +/* These functions return false on error, and save the error info in $^E */ +#define DeclOSFuncByORD(ret,name,o,at,args) \ + ret name at { unsigned long rc; return !CheckOSError(CallORD(ret,o,at,args)); } +#define DeclWinFuncByORD(ret,name,o,at,args) \ + ret name at { return SaveWinError(CallORD(ret,o,at,args)); } + +#define AssignFuncPByORD(p,o) (*(Perl_PFN*)&(p) = (loadByOrdinal(o, 1))) + +/* This flavor caches the procedure pointer (named as p__Win#name) locally */ +#define DeclWinFuncByORD_CACHE(ret,name,o,at,args) \ + DeclWinFuncByORD_CACHE_r(ret,name,o,at,args,0,1) + +/* This flavor may reset the last error before the call (if ret=0 may be OK) */ +#define DeclWinFuncByORD_CACHE_resetError(ret,name,o,at,args) \ + DeclWinFuncByORD_CACHE_r(ret,name,o,at,args,1,1) + +/* Two flavors below do the same as above, but do not auto-croak */ +/* This flavor caches the procedure pointer (named as p__Win#name) locally */ +#define DeclWinFuncByORD_CACHE_survive(ret,name,o,at,args) \ + DeclWinFuncByORD_CACHE_r(ret,name,o,at,args,0,0) + +/* This flavor may reset the last error before the call (if ret=0 may be OK) */ +#define DeclWinFuncByORD_CACHE_resetError_survive(ret,name,o,at,args) \ + DeclWinFuncByORD_CACHE_r(ret,name,o,at,args,1,0) + +#define DeclWinFuncByORD_CACHE_r(ret,name,o,at,args,r,die) \ + static ret (*CAT2(p__Win,name)) at; \ + static ret name at { \ + if (!CAT2(p__Win,name)) \ + AssignFuncPByORD(CAT2(p__Win,name), o); \ + if (r) ResetWinError(); \ + return SaveCroakWinError(CAT2(p__Win,name) args, die, "[Win]", STRINGIFY(name)); } + +/* These flavors additionally assume ORD is name with prepended ORD_Win */ +#define DeclWinFunc_CACHE(ret,name,at,args) \ + DeclWinFuncByORD_CACHE(ret,name,CAT2(ORD_Win,name),at,args) +#define DeclWinFunc_CACHE_resetError(ret,name,at,args) \ + DeclWinFuncByORD_CACHE_resetError(ret,name,CAT2(ORD_Win,name),at,args) +#define DeclWinFunc_CACHE_survive(ret,name,at,args) \ + DeclWinFuncByORD_CACHE_survive(ret,name,CAT2(ORD_Win,name),at,args) +#define DeclWinFunc_CACHE_resetError_survive(ret,name,at,args) \ + DeclWinFuncByORD_CACHE_resetError_survive(ret,name,CAT2(ORD_Win,name),at,args) + +void ResetWinError(void); +void CroakWinError(int die, char *name); + #define PERLLIB_MANGLE(s, n) perllib_mangle((s), (n)) char *perllib_mangle(char *, unsigned int); +typedef int (*Perl_PFN)(); +Perl_PFN loadByOrdinal(enum entries_ordinals ord, int fail); +extern const Perl_PFN * const pExtFCN; char *os2error(int rc); +int os2_stat(const char *name, struct stat *st); +int setpriority(int which, int pid, int val); +int getpriority(int which /* ignored */, int pid); + +#ifdef PERL_CORE +int os2_do_spawn(pTHX_ char *cmd); +int os2_do_aspawn(pTHX_ SV *really, void **vmark, void **vsp); +#endif + +#ifndef LOG_DAEMON + +/* Replacement for syslog.h */ +# define LOG_EMERG 0 /* system is unusable */ +# define LOG_ALERT 1 /* action must be taken immediately */ +# define LOG_CRIT 2 /* critical conditions */ +# define LOG_ERR 3 /* error conditions */ +# define LOG_WARNING 4 /* warning conditions */ +# define LOG_NOTICE 5 /* normal but significant condition */ +# define LOG_INFO 6 /* informational */ +# define LOG_DEBUG 7 /* debug-level messages */ + +# define LOG_PRIMASK 0x007 /* mask to extract priority part (internal) */ + /* extract priority */ +# define LOG_PRI(p) ((p) & LOG_PRIMASK) +# define LOG_MAKEPRI(fac, pri) (((fac) << 3) | (pri)) + +/* facility codes */ +# define LOG_KERN (0<<3) /* kernel messages */ +# define LOG_USER (1<<3) /* random user-level messages */ +# define LOG_MAIL (2<<3) /* mail system */ +# define LOG_DAEMON (3<<3) /* system daemons */ +# define LOG_AUTH (4<<3) /* security/authorization messages */ +# define LOG_SYSLOG (5<<3) /* messages generated internally by syslogd */ +# define LOG_LPR (6<<3) /* line printer subsystem */ +# define LOG_NEWS (7<<3) /* network news subsystem */ +# define LOG_UUCP (8<<3) /* UUCP subsystem */ +# define LOG_CRON (15<<3) /* clock daemon */ + /* other codes through 15 reserved for system use */ +# define LOG_LOCAL0 (16<<3) /* reserved for local use */ +# define LOG_LOCAL1 (17<<3) /* reserved for local use */ +# define LOG_LOCAL2 (18<<3) /* reserved for local use */ +# define LOG_LOCAL3 (19<<3) /* reserved for local use */ +# define LOG_LOCAL4 (20<<3) /* reserved for local use */ +# define LOG_LOCAL5 (21<<3) /* reserved for local use */ +# define LOG_LOCAL6 (22<<3) /* reserved for local use */ +# define LOG_LOCAL7 (23<<3) /* reserved for local use */ + +# define LOG_NFACILITIES 24 /* current number of facilities */ +# define LOG_FACMASK 0x03f8 /* mask to extract facility part */ + /* facility of pri */ +# define LOG_FAC(p) (((p) & LOG_FACMASK) >> 3) + +/* + * arguments to setlogmask. + */ +# define LOG_MASK(pri) (1 << (pri)) /* mask for one priority */ +# define LOG_UPTO(pri) ((1 << ((pri)+1)) - 1) /* all priorities through pri */ + +/* + * Option flags for openlog. + * + * LOG_ODELAY no longer does anything. + * LOG_NDELAY is the inverse of what it used to be. + */ +# define LOG_PID 0x01 /* log the pid with each message */ +# define LOG_CONS 0x02 /* log on the console if errors in sending */ +# define LOG_ODELAY 0x04 /* delay open until first syslog() (default) */ +# define LOG_NDELAY 0x08 /* don't delay open */ +# define LOG_NOWAIT 0x10 /* don't wait for console forks: DEPRECATED */ +# define LOG_PERROR 0x20 /* log to stderr as well */ + +#endif /* ************************************************************ */ #define Dos32QuerySysState DosQuerySysState |