summaryrefslogtreecommitdiff
path: root/gnu/usr.bin/perl/os2
diff options
context:
space:
mode:
authorTodd C. Miller <millert@cvs.openbsd.org>2002-10-27 22:25:41 +0000
committerTodd C. Miller <millert@cvs.openbsd.org>2002-10-27 22:25:41 +0000
commitd85c2f57f17d991a6ca78d3e1c9f3308a2bbb271 (patch)
tree8c9a359433cbb3488b0a848e99bd869c76295dfd /gnu/usr.bin/perl/os2
parent74cfb115ac810480c0000dc742b20383c1578bac (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/Changes161
-rw-r--r--gnu/usr.bin/perl/os2/Makefile.SHs276
-rw-r--r--gnu/usr.bin/perl/os2/OS2/ExtAttr/Makefile.PL2
-rw-r--r--gnu/usr.bin/perl/os2/OS2/PrfDB/Makefile.PL2
-rw-r--r--gnu/usr.bin/perl/os2/OS2/PrfDB/PrfDB.xs48
-rw-r--r--gnu/usr.bin/perl/os2/OS2/Process/Makefile.PL32
-rw-r--r--gnu/usr.bin/perl/os2/OS2/Process/Process.pm1110
-rw-r--r--gnu/usr.bin/perl/os2/OS2/Process/Process.xs837
-rw-r--r--gnu/usr.bin/perl/os2/OS2/REXX/Makefile.PL2
-rw-r--r--gnu/usr.bin/perl/os2/OS2/REXX/REXX.pm63
-rw-r--r--gnu/usr.bin/perl/os2/OS2/REXX/REXX.xs239
-rw-r--r--gnu/usr.bin/perl/os2/OS2/REXX/t/rx_cmprt.t8
-rw-r--r--gnu/usr.bin/perl/os2/OS2/REXX/t/rx_vrexx.t6
-rw-r--r--gnu/usr.bin/perl/os2/diff.configure32
-rw-r--r--gnu/usr.bin/perl/os2/dl_os2.c42
-rw-r--r--gnu/usr.bin/perl/os2/dlfcn.h4
-rw-r--r--gnu/usr.bin/perl/os2/os2.c1114
-rw-r--r--gnu/usr.bin/perl/os2/os2ish.h341
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