diff options
author | Larry Wall <lwall@sems.com> | 1996-08-10 15:24:58 +0000 |
---|---|---|
committer | Larry Wall <lwall@sems.com> | 1996-08-10 15:24:58 +0000 |
commit | 760ac839baf413929cd31cc32ffd6dba6b781a81 (patch) | |
tree | 010ae8135426972c27b065782284341c839dc2a0 /os2 | |
parent | 43cc1d52f97c5f21f3207f045444707e7be33927 (diff) | |
download | perl-760ac839baf413929cd31cc32ffd6dba6b781a81.tar.gz |
perl 5.003_02: [no incremental changelog available]
Diffstat (limited to 'os2')
41 files changed, 3901 insertions, 620 deletions
diff --git a/os2/Makefile.SHs b/os2/Makefile.SHs index 83227bb38b..72b4383c7d 100644 --- a/os2/Makefile.SHs +++ b/os2/Makefile.SHs @@ -41,6 +41,7 @@ perl5.def: perl.linkexp echo ' "dlopen"' >>$@ echo ' "dlsym"' >>$@ echo ' "dlerror"' >>$@ + echo ' "perl_init_i18nl10n"' >>$@ !NO!SUBS! if [ ! -z "$myttyname" ] ; then @@ -119,6 +120,11 @@ miniperl_: $& miniperlmain$(AOUT_OBJ_EXT) $(aout_perllib) ext.libs perl_: $& aout_perlmain$(AOUT_OBJ_EXT) $(aout_perllib) $(AOUT_DYNALOADER) $(aout_static_ext) ext.libs $(CC) $(LARGE) $(AOUT_CLDFLAGS) $(CCDLFLAGS) -o perl_ aout_perlmain$(AOUT_OBJ_EXT) $(AOUT_DYNALOADER) $(aout_static_ext) $(aout_perllib) `cat ext.libs` $(libs) +perl : perl__ + +perl__: $& perlmain$(OBJ_EXT) $(perllib) $(DYNALOADER) $(static_ext) ext.libs + $(CC) $(LARGE) $(CLDFLAGS) $(CCDLFLAGS) -o perl__ perlmain$(OBJ_EXT) $(DYNALOADER) $(static_ext) $(perllib) `cat ext.libs` $(libs) -Zlinker /PM:PM + aout_clean: -rm *perl_.* *.o *.a lib/auto/*/*.a ext/*/Makefile.aout @@ -128,13 +134,22 @@ 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 + - cd t && (rm -f perl_$(EXE_EXT); $(LNS) ../perl_$(EXE_EXT) perl$(EXE_EXT)) && ./perl TEST </dev/tty + +lib/auto/OS2/*/%.a : ext/OS2/%/Makefile.aout + cd ext/OS2/$(basename $(notdir $@)) ; make -f Makefile.aout config || echo "$make config failed, continuing anyway..." + cd ext/OS2/$(basename $(notdir $@)) ; make -f Makefile.aout LINKTYPE=static CCCDLFLAGS= 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= +.PRECIOUS : ext/%/Makefile.aout ext/OS2/%/Makefile.aout + +ext/OS2/%/Makefile.aout : miniperl_ + cd $(dir $@) ; ../../../miniperl_ -I ../../../lib Makefile.PL MAKEFILE=Makefile.aout INSTALLDIRS=perl + ext/%/Makefile.aout : miniperl_ - cd $(dir $@) ; ../../miniperl_ Makefile.PL MAKEFILE=Makefile.aout INSTALLDIRS=perl + cd $(dir $@) ; ../../miniperl_ -I ../../lib Makefile.PL MAKEFILE=Makefile.aout INSTALLDIRS=perl !NO!SUBS! diff --git a/os2/OS2/ExtAttr/Changes b/os2/OS2/ExtAttr/Changes new file mode 100644 index 0000000000..55fdc5f6d5 --- /dev/null +++ b/os2/OS2/ExtAttr/Changes @@ -0,0 +1,5 @@ +Revision history for Perl extension OS2::ExtAttr. + +0.01 Sun Apr 21 11:07:04 1996 + - original version; created by h2xs 1.16 + diff --git a/os2/OS2/ExtAttr/ExtAttr.pm b/os2/OS2/ExtAttr/ExtAttr.pm new file mode 100644 index 0000000000..bebbcc963e --- /dev/null +++ b/os2/OS2/ExtAttr/ExtAttr.pm @@ -0,0 +1,186 @@ +package OS2::ExtAttr; + +use strict; +use vars qw($VERSION @ISA @EXPORT); + +require Exporter; +require DynaLoader; + +@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( + +); +$VERSION = '0.01'; + +bootstrap OS2::ExtAttr $VERSION; + +# Preloaded methods go here. + +# Format of the array: +# 0 ead, 1 file name, 2 file handle. 3 length, 4 position, 5 need to write. + +sub TIEHASH { + my $class = shift; + my $ea = _create() || die "Cannot create EA: $!"; + my $file = shift; + my ($name, $handle); + if (ref $file eq 'GLOB' or ref \$file eq 'GLOB') { + die "File handle is not opened" unless $handle = fileno $file; + _read($ea, undef, $handle, 0); + } else { + $name = $file; + _read($ea, $name, 0, 0); + } + bless [$ea, $name, $handle, 0, 0, 0], $class; +} + +sub DESTROY { + my $eas = shift; + # 0 means: discard eas which are not in $eas->[0]. + _write( $eas->[0], $eas->[1], $eas->[2], 0) and die "Cannot write EA: $!" + if $eas->[5]; + _destroy( $eas->[0] ); +} + +sub FIRSTKEY { + my $eas = shift; + $eas->[3] = _count($eas->[0]); + $eas->[4] = 1; + return undef if $eas->[4] > $eas->[3]; + return _get_name($eas->[0], $eas->[4]); +} + +sub NEXTKEY { + my $eas = shift; + $eas->[4]++; + return undef if $eas->[4] > $eas->[3]; + return _get_name($eas->[0], $eas->[4]); +} + +sub FETCH { + my $eas = shift; + my $index = _find($eas->[0], shift); + return undef if $index <= 0; + return value($eas->[0], $index); +} + +sub EXISTS { + my $eas = shift; + return _find($eas->[0], shift) > 0; +} + +sub STORE { + my $eas = shift; + $eas->[5] = 1; + add($eas->[0], shift, shift) > 0 or die "Error setting EA: $!"; +} + +sub DELETE { + my $eas = shift; + my $index = _find($eas->[0], shift); + return undef if $index <= 0; + my $value = value($eas->[0], $index); + _delete($eas->[0], $index) and die "Error deleting EA: $!"; + $eas->[5] = 1; + return $value; +} + +sub CLEAR { + my $eas = shift; + _clear($eas->[0]); + $eas->[5] = 1; +} + +# Here are additional methods: + +*new = \&TIEHASH; + +sub copy { + my $eas = shift; + my $file = shift; + my ($name, $handle); + if (ref $file eq 'GLOB' or ref \$file eq 'GLOB') { + die "File handle is not opened" unless $handle = fileno $file; + _write($eas->[0], undef, $handle, 0) or die "Cannot write EA: $!"; + } else { + $name = $file; + _write($eas->[0], $name, 0, 0) or die "Cannot write EA: $!"; + } +} + +sub update { + my $eas = shift; + # 0 means: discard eas which are not in $eas->[0]. + _write( $eas->[0], $eas->[1], $eas->[2], 0) and die "Cannot write EA: $!"; +} + +# Autoload methods go after =cut, and are processed by the autosplit program. + +1; +__END__ +# Below is the stub of documentation for your module. You better edit it! + +=head1 NAME + +OS2::ExtAttr - Perl access to extended attributes. + +=head1 SYNOPSIS + + use OS2::ExtAttr; + tie %ea, 'OS2::ExtAttr', 'my.file'; + print $ea{eaname}; + $ea{myfield} = 'value'; + + untie %ea; + +=head1 DESCRIPTION + +The package provides low-level and high-level interface to Extended +Attributes under OS/2. + +=head2 High-level interface: C<tie> + +The only argument of tie() is a file name, or an open file handle. + +Note that all the changes of the tied hash happen in core, to +propagate it to disk the tied hash should be untie()ed or should go +out of scope. Alternatively, one may use the low-level C<update> +method on the corresponding object. Example: + + tied(%hash)->update; + +Note also that setting/getting EA flag is not supported by the +high-level interface, one should use the low-level interface +instead. To use it on a tied hash one needs undocumented way to find +C<eas> give the tied hash. + +=head2 Low-level interface + +Two low-level methods are supported by the objects: copy() and +update(). The copy() takes one argument: the name of a file to copy +the attributes to, or an opened file handle. update() takes no +arguments, and is discussed above. + +Three convenience functions are provided: + + value($eas, $key) + add($eas, $key, $value [, $flag]) + replace($eas, $key, $value [, $flag]) + +The default value for C<flag> is 0. + +In addition, all the C<_ea_*> and C<_ead_*> functions defined in EMX +library are supported, with leading C<_ea/_ead> stripped. + +=head1 AUTHOR + +Ilya Zakharevich, ilya@math.ohio-state.edu + +=head1 SEE ALSO + +perl(1). + +=cut diff --git a/os2/OS2/ExtAttr/ExtAttr.xs b/os2/OS2/ExtAttr/ExtAttr.xs new file mode 100644 index 0000000000..566b6595c8 --- /dev/null +++ b/os2/OS2/ExtAttr/ExtAttr.xs @@ -0,0 +1,193 @@ +#ifdef __cplusplus +extern "C" { +#endif +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" +#ifdef __cplusplus +} +#endif + +#include "myea.h" + +SV * +my_eadvalue(_ead ead, int index) +{ + SV *sv; + int size = _ead_value_size(ead, index); + void *p; + + if (size == -1) { + die("Error getting size of EA: %s", strerror(errno)); + } + p = _ead_get_value(ead, index); + return newSVpv((char*)p, size); +} + +#define my_eadreplace(ead, index, sv, flag) \ + _ead_replace((ead), (index), flag, SvPVX(sv), SvCUR(sv)) + +#define my_eadadd(ead, name, sv, flag) \ + _ead_add((ead), (name), flag, SvPVX(sv), SvCUR(sv)) + + +MODULE = OS2::ExtAttr PACKAGE = OS2::ExtAttr PREFIX = my_ead + +SV * +my_eadvalue(ead, index) + _ead ead + int index + +int +my_eadreplace(ead, index, sv, flag = 0) + _ead ead + int index + SV * sv + int flag + +int +my_eadadd(ead, name, sv, flag = 0) + _ead ead + char * name + SV * sv + int flag + +MODULE = OS2::ExtAttr PACKAGE = OS2::ExtAttr PREFIX = _ea + + +void +_ea_free(ptr) + struct _ea * ptr + +int +_ea_get(dst, path, handle, name) + struct _ea * dst + char * path + int handle + char * name + +int +_ea_put(src, path, handle, name) + struct _ea * src + char * path + int handle + char * name + +int +_ea_remove(path, handle, name) + char * path + int handle + char * name + +MODULE = OS2::ExtAttr PACKAGE = OS2::ExtAttr PREFIX = _ead + +int +_ead_add(ead, name, flags, value, size) + _ead ead + char * name + int flags + void * value + int size + +void +_ead_clear(ead) + _ead ead + +int +_ead_copy(dst_ead, src_ead, src_index) + _ead dst_ead + _ead src_ead + int src_index + +int +_ead_count(ead) + _ead ead + +_ead +_ead_create() + +int +_ead_delete(ead, index) + _ead ead + int index + +void +_ead_destroy(ead) + _ead ead + +int +_ead_fea2list_size(ead) + _ead ead + +void * +_ead_fea2list_to_fealist(src) + void * src + +void * +_ead_fealist_to_fea2list(src) + void * src + +int +_ead_find(ead, name) + _ead ead + char * name + +void * +_ead_get_fea2list(ead) + _ead ead + +int +_ead_get_flags(ead, index) + _ead ead + int index + +char * +_ead_get_name(ead, index) + _ead ead + int index + +void * +_ead_get_value(ead, index) + _ead ead + int index + +int +_ead_name_len(ead, index) + _ead ead + int index + +int +_ead_read(ead, path, handle, flags) + _ead ead + char * path + int handle + int flags + +int +_ead_replace(ead, index, flags, value, size) + _ead ead + int index + int flags + void * value + int size + +void +_ead_sort(ead) + _ead ead + +int +_ead_use_fea2list(ead, src) + _ead ead + void * src + +int +_ead_value_size(ead, index) + _ead ead + int index + +int +_ead_write(ead, path, handle, flags) + _ead ead + char * path + int handle + int flags diff --git a/os2/OS2/ExtAttr/MANIFEST b/os2/OS2/ExtAttr/MANIFEST new file mode 100644 index 0000000000..b1a8e80e77 --- /dev/null +++ b/os2/OS2/ExtAttr/MANIFEST @@ -0,0 +1,8 @@ +Changes +ExtAttr.pm +ExtAttr.xs +MANIFEST +Makefile.PL +myea.h +t/os2_ea.t +typemap diff --git a/os2/OS2/ExtAttr/Makefile.PL b/os2/OS2/ExtAttr/Makefile.PL new file mode 100644 index 0000000000..4e8498f10c --- /dev/null +++ b/os2/OS2/ExtAttr/Makefile.PL @@ -0,0 +1,10 @@ +use ExtUtils::MakeMaker; +# See lib/ExtUtils/MakeMaker.pm for details of how to influence +# the contents of the Makefile that is written. +WriteMakefile( + 'NAME' => 'OS2::ExtAttr', + 'VERSION_FROM' => 'ExtAttr.pm', # finds $VERSION + 'LIBS' => [''], # e.g., '-lm' + 'DEFINE' => '', # e.g., '-DHAVE_SOMETHING' + 'INC' => '', # e.g., '-I/usr/include/other' +); diff --git a/os2/OS2/ExtAttr/myea.h b/os2/OS2/ExtAttr/myea.h new file mode 100644 index 0000000000..ec4dc81f99 --- /dev/null +++ b/os2/OS2/ExtAttr/myea.h @@ -0,0 +1,2 @@ +#include <sys/ea.h> +#include <sys/ead.h> diff --git a/os2/OS2/ExtAttr/t/os2_ea.t b/os2/OS2/ExtAttr/t/os2_ea.t new file mode 100644 index 0000000000..c1024193c1 --- /dev/null +++ b/os2/OS2/ExtAttr/t/os2_ea.t @@ -0,0 +1,79 @@ +BEGIN { + chdir 't' if -d 't/lib'; + @INC = '../lib' if -d 'lib'; + require Config; import Config; + if (-d 'lib' and $Config{'extensions'} !~ /\bOS2::REXX\b/) { + print "1..0\n"; + exit 0; + } +} + +# Before `make install' is performed this script should be runnable with +# `make test'. After `make install' it should work as `perl test.pl' + +######################### We start with some black magic to print on failure. + +# Change 1..1 below to 1..last_test_to_print . +# (It may become useful if the test is moved to ./t subdirectory.) + +BEGIN { $| = 1; print "1..21\n"; } +END {print "not ok 1\n" unless $loaded;} +use OS2::ExtAttr; +$loaded = 1; +print "ok 1\n"; + +######################### End of black magic. + +# Insert your test code below (better if it prints "ok 13" +# (correspondingly "not ok 13") depending on the success of chunk 13 +# of the test code): + +system 'cmd', '/c', 'del t.out'; +system 'cmd', '/c', 'echo OK > t.out'; + +{ + my %a; + tie %a, 'OS2::ExtAttr', 't.out'; + print "ok 2\n"; + + keys %a == 0 ? print "ok 3\n" : print "not ok 3\n"; + $a{'++'} = '---'; + print "ok 4\n"; + $a{'AAA'} = 'xyz'; + print "ok 5\n"; +} + +{ + my %a; + tie %a, 'OS2::ExtAttr', 't.out'; + print "ok 6\n"; + + my $c = keys %a; + $c == 2 ? print "ok 7\n" : print "not ok 7\n# c=$c\n"; + my @b = sort keys %a; + "@b" eq '++ AAA' ? print "ok 8\n" : print "not ok 8\n# keys=`@b'\n"; + $a{'++'} eq '---' ? print "ok 9\n" : print "not ok 9\n";; + $a{'AAA'} eq 'xyz' ? print "ok 10\n" : print "not ok 10\n# aaa->`$a{AAA}'\n"; + $c = delete $a{'++'}; + $c eq '---' ? print "ok 11\n" : print "not ok 11\n# deleted->`$c'\n";; +} + +print "ok 12\n"; + +{ + my %a; + tie %a, 'OS2::ExtAttr', 't.out'; + print "ok 13\n"; + + keys %a == 1 ? print "ok 14\n" : print "not ok 14\n"; + my @b = sort keys %a; + "@b" eq 'AAA' ? print "ok 15\n" : print "not ok 15\n"; + $a{'AAA'} eq 'xyz' ? print "ok 16\n" : print "not ok 16\n";; + ! exists $a{'+'} ? print "ok 17\n" : print "not ok 17\n";; + ! defined $a{'+'} ? print "ok 18\n" : print "not ok 18\n# ->`$a{'++'}'\n";; + ! exists $a{'++'} ? print "ok 19\n" : print "not ok 19\n";; + ! defined $a{'++'} ? print "ok 20\n" : print "not ok 20\n# ->`$a{'++'}'\n";; +} + +print "ok 21\n"; + diff --git a/os2/OS2/ExtAttr/typemap b/os2/OS2/ExtAttr/typemap new file mode 100644 index 0000000000..a5ff8d63ac --- /dev/null +++ b/os2/OS2/ExtAttr/typemap @@ -0,0 +1,2 @@ +struct _ea * T_PTR +_ead T_PTR diff --git a/os2/OS2/PrfDB/Changes b/os2/OS2/PrfDB/Changes new file mode 100644 index 0000000000..3e8bf3f580 --- /dev/null +++ b/os2/OS2/PrfDB/Changes @@ -0,0 +1,5 @@ +Revision history for Perl extension OS2::PrfDB. + +0.01 Tue Mar 26 19:35:27 1996 + - original version; created by h2xs 1.16 +0.02: Field do-not-close added to OS2::Prf::Hini. diff --git a/os2/OS2/PrfDB/MANIFEST b/os2/OS2/PrfDB/MANIFEST new file mode 100644 index 0000000000..fb96b03c5d --- /dev/null +++ b/os2/OS2/PrfDB/MANIFEST @@ -0,0 +1,7 @@ +Changes +MANIFEST +Makefile.PL +PrfDB.pm +PrfDB.xs +t/os2_prfdb.t +typemap diff --git a/os2/OS2/PrfDB/Makefile.PL b/os2/OS2/PrfDB/Makefile.PL new file mode 100644 index 0000000000..c591c0490c --- /dev/null +++ b/os2/OS2/PrfDB/Makefile.PL @@ -0,0 +1,10 @@ +use ExtUtils::MakeMaker; +# See lib/ExtUtils/MakeMaker.pm for details of how to influence +# the contents of the Makefile that is written. +WriteMakefile( + 'NAME' => 'OS2::PrfDB', + 'VERSION_FROM' => 'PrfDB.pm', # finds $VERSION + 'LIBS' => [''], # e.g., '-lm' + 'DEFINE' => '', # e.g., '-DHAVE_SOMETHING' + 'INC' => '', # e.g., '-I/usr/include/other' +); diff --git a/os2/OS2/PrfDB/PrfDB.pm b/os2/OS2/PrfDB/PrfDB.pm new file mode 100644 index 0000000000..d404c8b1d3 --- /dev/null +++ b/os2/OS2/PrfDB/PrfDB.pm @@ -0,0 +1,314 @@ +package OS2::PrfDB; + +use strict; +use vars qw($VERSION @ISA @EXPORT); + +require Exporter; +require DynaLoader; + +@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( + AnyIni UserIni SystemIni + ); +$VERSION = '0.02'; + +bootstrap OS2::PrfDB $VERSION; + +# Preloaded methods go here. + +sub AnyIni { + new_from_int OS2::PrfDB::Hini OS2::Prf::System(0), + 'Anyone of two "systemish" databases', 1; +} + +sub UserIni { + new_from_int OS2::PrfDB::Hini OS2::Prf::System(1), 'User settings database', 1; +} + +sub SystemIni { + new_from_int OS2::PrfDB::Hini OS2::Prf::System(2),'System settings database',1; +} + +use vars qw{$debug @ISA}; +use Tie::Hash; +@ISA = qw{Tie::Hash}; + +# Internal structure 0 => HINI, 1 => array of entries, 2 => iterator. + +sub TIEHASH { + die "Usage: tie %arr, OS2::PrfDB, filename\n" unless @_ == 2; + my ($obj, $file) = @_; + my $hini = ref $file eq 'OS2::PrfDB::Hini' ? $file + : new OS2::PrfDB::Hini $file; + die "Error opening profile database `$file': $!" unless $hini; + # print "tiehash `@_', hini $hini\n" if $debug; + bless [$hini, undef, undef]; +} + +sub STORE { + my ($self, $key, $val) = @_; + die unless @_ == 3; + die unless ref $val eq 'HASH'; + my %sub; + tie %sub, 'OS2::PrfDB::Sub', $self->[0], $key; + %sub = %$val; +} + +sub FETCH { + my ($self, $key) = @_; + die unless @_ == 2; + my %sub; + tie %sub, 'OS2::PrfDB::Sub', $self->[0], $key; + \%sub; +} + +sub DELETE { + my ($self, $key) = @_; + die unless @_ == 2; + my %sub; + tie %sub, 'OS2::PrfDB::Sub', $self->[0], $key; + %sub = (); +} + +# CLEAR ???? - deletion of the whole + +sub EXISTS { + my ($self, $key) = @_; + die unless @_ == 2; + return OS2::Prf::GetLength($self->[0]->[0], $key, undef) >= 0; +} + +sub FIRSTKEY { + my $self = shift; + my $keys = OS2::Prf::Get($self->[0]->[0], undef, undef); + return undef unless defined $keys; + chop($keys); + $self->[1] = [split /\0/, $keys]; + # print "firstkey1 $self, `$self->[3]->[0], $self->[3]->[1]'\n" if $debug; + $self->[2] = 0; + return $self->[1]->[0]; + # OS2::Prf::Get($self->[0]->[0], $self->[2], $self->[3]->[0])); +} + +sub NEXTKEY { + # print "nextkey `@_'\n" if $debug; + my $self = shift; + return undef unless $self->[2]++ < $#{$self->[1]}; + my $key = $self->[1]->[$self->[2]]; + return $key; #, OS2::Prf::Get($self->[0]->[0], $self->[2], $key)); +} + +package OS2::PrfDB::Hini; + +sub new { + die "Usage: new OS2::PrfDB::Hini filename\n" unless @_ == 2; + shift; + my $file = shift; + my $hini = OS2::Prf::Open($file); + die "Error opening profile database `$file': $!" unless $hini; + bless [$hini, $file]; +} + +# Takes HINI and file name: + +sub new_from_int { shift; bless [@_] } + +# Internal structure 0 => HINI, 1 => filename, 2 => do-not-close. + +sub DESTROY { + my $self = shift; + my $hini = $self->[0]; + unless ($self->[2]) { + OS2::Prf::Close($hini) or die "Error closing profile `$self->[1]': $!"; + } +} + +package OS2::PrfDB::Sub; +use vars qw{$debug @ISA}; +use Tie::Hash; +@ISA = qw{Tie::Hash}; + +# Internal structure 0 => HINI, 1 => array of entries, 2 => iterator, +# 3 => appname. + +sub TIEHASH { + die "Usage: tie %arr, OS2::PrfDB::Sub, filename, appname\n" unless @_ == 3; + my ($obj, $file, $app) = @_; + my $hini = ref $file eq 'OS2::PrfDB::Hini' ? $file + : new OS2::PrfDB::Hini $file; + die "Error opening profile database `$file': $!" unless $hini; + # print "tiehash `@_', hini $hini\n" if $debug; + bless [$hini, undef, undef, $app]; +} + +sub STORE { + my ($self, $key, $val) = @_; + die unless @_ == 3; + OS2::Prf::Set($self->[0]->[0], $self->[3], $key, $val); +} + +sub FETCH { + my ($self, $key) = @_; + die unless @_ == 2; + OS2::Prf::Get($self->[0]->[0], $self->[3], $key); +} + +sub DELETE { + my ($self, $key) = @_; + die unless @_ == 2; + OS2::Prf::Set($self->[0]->[0], $self->[3], $key, undef); +} + +# CLEAR ???? - deletion of the whole + +sub EXISTS { + my ($self, $key) = @_; + die unless @_ == 2; + return OS2::Prf::GetLength($self->[0]->[0], $self->[3], $key) >= 0; +} + +sub FIRSTKEY { + my $self = shift; + my $keys = OS2::Prf::Get($self->[0]->[0], $self->[3], undef); + return undef unless defined $keys; + chop($keys); + $self->[1] = [split /\0/, $keys]; + # print "firstkey1 $self, `$self->[3]->[0], $self->[3]->[1]'\n" if $debug; + $self->[2] = 0; + return $self->[1]->[0]; + # OS2::Prf::Get($self->[0]->[0], $self->[2], $self->[3]->[0])); +} + +sub NEXTKEY { + # print "nextkey `@_'\n" if $debug; + my $self = shift; + return undef unless $self->[2]++ < $#{$self->[1]}; + my $key = $self->[1]->[$self->[2]]; + return $key; #, OS2::Prf::Get($self->[0]->[0], $self->[2], $key)); +} + +# Autoload methods go after =cut, and are processed by the autosplit program. + +1; +__END__ +# Below is the stub of documentation for your module. You better edit it! + +=head1 NAME + +OS2::PrfDB - Perl extension for access to OS/2 setting database. + +=head1 SYNOPSIS + + use OS2::PrfDB; + tie %settings, OS2::PrfDB, 'my.ini'; + tie %subsettings, OS2::PrfDB::Sub, 'my.ini', 'mykey'; + + print "$settings{firstkey}{subkey}\n"; + print "$subsettings{subkey}\n"; + + tie %system, OS2::PrfDB, SystemIni; + $system{myapp}{mykey} = "myvalue"; + + +=head1 DESCRIPTION + +The extention provides both high-level and low-level access to .ini +files. + +=head2 High level access + +High-level access is the tie-hash access via two packages: +C<OS2::PrfDB> and C<OS2::PrfDB::Sub>. First one supports one argument, +the name of the file to open, the second one the name of the file to +open and so called I<Application name>, or the primary key of the +database. + + tie %settings, OS2::PrfDB, 'my.ini'; + tie %subsettings, OS2::PrfDB::Sub, 'my.ini', 'mykey'; + +One may substitute a handle for already opened ini-file instead of the +file name (obtained via low-level access functions). In particular, 3 +functions SystemIni(), UserIni(), and AnyIni() provide handles to the +"systemish" databases. AniIni will read from both, and write into User +database. + +=head2 Low-level access + +Low-level access functions reside in the package C<OS2::Prf>. They are + +=over 14 + +=item C<Open(file)> + +Opens the database, returns an I<integer handle>. + +=item C<Close(hndl)> + +Closes the database given an I<integer handle>. + +=item C<Get(hndl, appname, key)> + +Retrieves data from the database given 2-part-key C<appname> C<key>. +If C<key> is C<undef>, return the "\0" delimited list of C<key>s, +terminated by \0. If C<appname> is C<undef>, returns the list of +possible C<appname>s in the same form. + +=item C<GetLength(hndl, appname, key)> + +Same as above, but returns the length of the value. + +=item C<Set(hndl, appname, key, value [ , length ])> + +Sets the value. If the C<value> is not defined, removes the C<key>. If +the C<key> is not defined, removes the C<appname>. + +=item C<System(val)> + +Return an I<integer handle> associated with the system database. If +C<val> is 1, it is I<User> database, if 2, I<System> database, if +0, handle for "both" of them: the handle works for read from any one, +and for write into I<User> one. + +=item C<Profiles()> + +returns a reference to a list of two strings, giving names of the +I<User> and I<System> databases. + +=item C<SetUser(file)> + +B<(Not tested.)> Sets the profile name of the I<User> database. The +application should have a message queue to use this function! + +=back + +=head2 Integer handles + +To convert a name or an integer handle into an object acceptable as +argument to tie() interface, one may use the following functions from +the package C<OS2::Prf::Hini>: + +=over 14 + +=item C<new(package, file)> + +=item C<new_from_int(package, int_hndl [ , filename ])> + +=back + +=head2 Exports + +SystemIni(), UserIni(), and AnyIni(). + +=head1 AUTHOR + +Ilya Zakharevich, ilya@math.ohio-state.edu + +=head1 SEE ALSO + +perl(1). + +=cut + diff --git a/os2/OS2/PrfDB/PrfDB.xs b/os2/OS2/PrfDB/PrfDB.xs new file mode 100644 index 0000000000..a5b2c89ca6 --- /dev/null +++ b/os2/OS2/PrfDB/PrfDB.xs @@ -0,0 +1,131 @@ +#define INCL_WINSHELLDATA /* Or use INCL_WIN, INCL_PM, */ + +#ifdef __cplusplus +extern "C" { +#endif +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" +#include <os2.h> +#ifdef __cplusplus +} +#endif + +#define Prf_Open(pszFileName) SaveWinError(PrfOpenProfile(Perl_hab, (pszFileName))) +#define Prf_Close(hini) (!CheckWinError(PrfCloseProfile(hini))) + +SV * +Prf_Get(HINI hini, PSZ app, PSZ key) { + ULONG len; + BOOL rc; + SV *sv; + + if (CheckWinError(PrfQueryProfileSize(hini, app, key, &len))) return &sv_undef; + sv = newSVpv("", 0); + SvGROW(sv, len); + if (CheckWinError(PrfQueryProfileData(hini, app, key, SvPVX(sv), &len)) + || (len == 0 && (app == NULL || key == NULL))) { /* Somewhy needed. */ + SvREFCNT_dec(sv); + return &sv_undef; + } + SvCUR_set(sv, len); + *SvEND(sv) = 0; + return sv; +} + +U32 +Prf_GetLength(HINI hini, PSZ app, PSZ key) { + U32 len; + + if (CheckWinError(PrfQueryProfileSize(hini, app, key, &len))) return -1; + return len; +} + +#define Prf_Set(hini, app, key, s, l) \ + (!(CheckWinError(PrfWriteProfileData(hini, app, key, s, l)))) + +#define Prf_System(key) \ + ( (key) ? ( (key) == 1 ? HINI_USERPROFILE \ + : ( (key) == 2 ? HINI_SYSTEMPROFILE \ + : (die("Wrong profile id %i", key), 0) )) \ + : HINI_PROFILE) + +SV* +Prf_Profiles() +{ + AV *av = newAV(); + SV *rv; + char user[257]; + char system[257]; + PRFPROFILE info = { 257, user, 257, system}; + + if (CheckWinError(PrfQueryProfile(Perl_hab, &info))) return &sv_undef; + if (info.cchUserName > 257 || info.cchSysName > 257) + die("Panic: Profile names too long"); + av_push(av, newSVpv(user, info.cchUserName - 1)); + av_push(av, newSVpv(system, info.cchSysName - 1)); + rv = newRV((SV*)av); + SvREFCNT_dec(av); + return rv; +} + +BOOL +Prf_SetUser(SV *sv) +{ + char user[257]; + char system[257]; + PRFPROFILE info = { 257, user, 257, system}; + + 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 (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)); +} + +MODULE = OS2::PrfDB PACKAGE = OS2::Prf PREFIX = Prf_ + +HINI +Prf_Open(pszFileName) + PSZ pszFileName; + +BOOL +Prf_Close(hini) + HINI hini; + +SV * +Prf_Get(hini, app, key) + HINI hini; + PSZ app; + PSZ key; + +int +Prf_Set(hini, app, key, s, l = (SvPOK(ST(3)) ? SvCUR(ST(3)): -1)) + HINI hini; + PSZ app; + PSZ key; + PSZ s; + ULONG l; + +U32 +Prf_GetLength(hini, app, key) + HINI hini; + PSZ app; + PSZ key; + +HINI +Prf_System(key) + int key; + +SV* +Prf_Profiles() + +BOOL +Prf_SetUser(sv) + SV *sv + +BOOT: + Acquire_hab(); diff --git a/os2/OS2/PrfDB/t/os2_prfdb.t b/os2/OS2/PrfDB/t/os2_prfdb.t new file mode 100644 index 0000000000..4c0883db50 --- /dev/null +++ b/os2/OS2/PrfDB/t/os2_prfdb.t @@ -0,0 +1,185 @@ +BEGIN { + chdir 't' if -d 't/lib'; + @INC = '../lib' if -d 'lib'; + require Config; import Config; + if (-d 'lib' and $Config{'extensions'} !~ /\bOS2::PrfDB\b/) { + print "1..0\n"; + exit 0; + } +} + +# Before `make install' is performed this script should be runnable with +# `make test'. After `make install' it should work as `perl test.pl' + +######################### We start with some black magic to print on failure. + +# Change 1..1 below to 1..last_test_to_print . +# (It may become useful if the test is moved to ./t subdirectory.) + +BEGIN { $| = 1; print "1..48\n"; } +END {print "not ok 1\n" unless $loaded;} +use OS2::PrfDB; +$loaded = 1; +use strict; + +print "ok 1\n"; + +######################### End of black magic. + +# Insert your test code below (better if it prints "ok 13" +# (correspondingly "not ok 13") depending on the success of chunk 13 +# of the test code): + +my $inifile = "my.ini"; + +unlink $inifile if -w $inifile; + +my $ini = OS2::Prf::Open($inifile); +print( ($ini ? "": "not "), "ok 2\n# HINI=`$ini'\n"); + +print( (OS2::Prf::GetLength($ini,'aaa', 'bbb') != -1) ? + "not ok 3\n# err: `$^E'\n" : "ok 3\n"); + + +print( OS2::Prf::Set($ini,'aaa', 'bbb','xyz') ? "ok 4\n" : + "not ok 4\n# err: `$^E'\n"); + +my $len = OS2::Prf::GetLength($ini,'aaa', 'bbb'); +print( $len == 3 ? "ok 5\n" : "not ok 5# len: `$len' err: `$^E'\n"); + +my $val = OS2::Prf::Get($ini,'aaa', 'bbb'); +print( $val eq 'xyz' ? "ok 6\n" : "not ok 6# val: `$val' err: `$^E'\n"); + +$val = OS2::Prf::Get($ini,'aaa', undef); +print( $val eq "bbb\0" ? "ok 7\n" : "not ok 7# val: `$val' err: `$^E'\n"); + +$val = OS2::Prf::Get($ini, undef, undef); +print( $val eq "aaa\0" ? "ok 8\n" : "not ok 8# val: `$val' err: `$^E'\n"); + +my $res = OS2::Prf::Set($ini,'aaa', 'bbb',undef); +print( $res ? "ok 9\n" : "not ok 9# err: `$^E'\n"); + +$val = OS2::Prf::Get($ini, undef, undef); +print( (! defined $val) ? "ok 10\n" : "not ok 10# val: `$val' err: `$^E'\n"); + +$val = OS2::Prf::Get($ini,'aaa', undef); +print( (! defined $val) ? "ok 11\n" : "not ok 11# val: `$val' err: `$^E'\n"); + +print((OS2::Prf::Close($ini) ? "" : "not ") . "ok 12\n"); + +my $files = OS2::Prf::Profiles(); +print( (defined $files) ? "ok 13\n" : "not ok 13# err: `$^E'\n"); +print( (@$files == 2) ? "ok 14\n" : "not ok 14# `@$files' err: `$^E'\n"); +print "# `@$files'\n"; + +$ini = OS2::Prf::Open($inifile); +print( ($ini ? "": "not "), "ok 15\n# HINI=`$ini'\n"); + + +print( OS2::Prf::Set($ini,'aaa', 'ccc','xyz') ? "ok 16\n" : + "not ok 16\n# err: `$^E'\n"); + +print( OS2::Prf::Set($ini,'aaa', 'ddd','123') ? "ok 17\n" : + "not ok 17\n# err: `$^E'\n"); + +print( OS2::Prf::Set($ini,'bbb', 'xxx','abc') ? "ok 18\n" : + "not ok 18\n# err: `$^E'\n"); + +print( OS2::Prf::Set($ini,'bbb', 'yyy','456') ? "ok 19\n" : + "not ok 19\n# err: `$^E'\n"); + +my %hash1; + +tie %hash1, 'OS2::PrfDB::Sub', $inifile, 'aaa'; +$OS2::PrfDB::Sub::debug = 1; +print "ok 20\n"; + +my @a1 = keys %hash1; +print (@a1 == 2 ? "ok 21\n" : "not ok 21\n# `@a1'\n"); + +my @a2 = sort @a1; +print ("@a2" eq "ccc ddd" ? "ok 22\n" : "not ok 22\n# `@a2'\n"); + +$val = $hash1{ccc}; +print ($val eq "xyz" ? "ok 23\n" : "not ok 23\n# `$val'\n"); + +$val = $hash1{ddd}; +print ($val eq "123" ? "ok 24\n" : "not ok 24\n# `$val'\n"); + +print (exists $hash1{ccc} ? "ok 25\n" : "not ok 25\n# `$val'\n"); + +print (!exists $hash1{hhh} ? "ok 26\n" : "not ok 26\n# `$val'\n"); + +$hash1{hhh} = 12; +print (exists $hash1{hhh} ? "ok 27\n" : "not ok 27\n# `$val'\n"); + +$val = $hash1{hhh}; +print ($val eq "12" ? "ok 28\n" : "not ok 28\n# `$val'\n"); + +delete $hash1{ccc}; + +untie %hash1; +print "ok 29\n"; + +tie %hash1, 'OS2::PrfDB::Sub', $inifile, 'aaa'; +print "ok 30\n"; + +@a1 = keys %hash1; +print (@a1 == 2 ? "ok 31\n" : "not ok 31\n# `@a1'\n"); + +@a2 = sort @a1; +print ("@a2" eq "ddd hhh" ? "ok 32\n" : "not ok 32\n# `@a2'\n"); + +print (exists $hash1{hhh} ? "ok 33\n" : "not ok 33\n# `$val'\n"); + +$val = $hash1{hhh}; +print ($val eq "12" ? "ok 34\n" : "not ok 34\n# `$val'\n"); + +%hash1 = (); +print "ok 35\n"; + +%hash1 = ( hhh => 12, ddd => 5); + +untie %hash1; + +my %hash; + +tie %hash, 'OS2::PrfDB', $inifile; +print "ok 36\n"; + +@a1 = keys %hash; +print (@a1 == 2 ? "ok 37\n" : "not ok 37\n# `@a1'\n"); + +@a2 = sort @a1; +print ("@a2" eq "aaa bbb" ? "ok 38\n" : "not ok 38\n# `@a2'\n"); + +print (exists $hash{aaa} ? "ok 39\n" : "not ok 39\n# `$val'\n"); + +$val = $hash{aaa}; +print (ref $val eq "HASH" ? "ok 40\n" : "not ok 40\n# `$val'\n"); + +%hash1 = %$val; +print "ok 41\n"; + +@a1 = keys %hash1; +print (@a1 == 2 ? "ok 42\n" : "not ok 31\n# `@a1'\n"); + +@a2 = sort @a1; +print ("@a2" eq "ddd hhh" ? "ok 43\n" : "not ok 43\n# `@a2'\n"); + +print (exists $hash1{hhh} ? "ok 44\n" : "not ok 44\n# `$val'\n"); + +$val = $hash1{hhh}; +print ($val eq "12" ? "ok 45\n" : "not ok 45\n# `$val'\n"); + +$hash{nnn}{mmm} = 67; +print "ok 46\n"; + +untie %hash; + +my %hash2; + +tie %hash2, 'OS2::PrfDB', $inifile; +print "ok 47\n"; + +print ($hash2{nnn}->{mmm} eq "67" ? "ok 48\n" : "not ok 48\n# `$val'\n"); diff --git a/os2/OS2/PrfDB/typemap b/os2/OS2/PrfDB/typemap new file mode 100644 index 0000000000..0b91f3750a --- /dev/null +++ b/os2/OS2/PrfDB/typemap @@ -0,0 +1,14 @@ +BOOL T_IV +ULONG T_IV +HINI T_IV +HAB T_IV +PSZ T_PVNULL + +############################################################################# +INPUT +T_PVNULL + $var = ( SvOK($arg) ? ($type)SvPV($arg,na) : NULL ) +############################################################################# +OUTPUT +T_PVNULL + sv_setpv((SV*)$arg, $var); diff --git a/os2/OS2/Process/MANIFEST b/os2/OS2/Process/MANIFEST new file mode 100644 index 0000000000..0d90d15fca --- /dev/null +++ b/os2/OS2/Process/MANIFEST @@ -0,0 +1,4 @@ +MANIFEST +Makefile.PL +Process.pm +Process.xs diff --git a/os2/OS2/Process/Makefile.PL b/os2/OS2/Process/Makefile.PL new file mode 100644 index 0000000000..ff4deabef6 --- /dev/null +++ b/os2/OS2/Process/Makefile.PL @@ -0,0 +1,10 @@ +use ExtUtils::MakeMaker; +# See lib/ExtUtils/MakeMaker.pm for details of how to influence +# the contents of the Makefile that is written. +WriteMakefile( + 'NAME' => 'OS2::Process', + 'VERSION' => '0.1', + 'LIBS' => [''], # e.g., '-lm' + 'DEFINE' => '', # e.g., '-DHAVE_SOMETHING' + 'INC' => '', # e.g., '-I/usr/include/other' +); diff --git a/os2/OS2/Process/Process.pm b/os2/OS2/Process/Process.pm new file mode 100644 index 0000000000..9216bb1e05 --- /dev/null +++ b/os2/OS2/Process/Process.pm @@ -0,0 +1,112 @@ +package OS2::Process; + +require Exporter; +require DynaLoader; +require AutoLoader; + +@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( + P_BACKGROUND + P_DEBUG + P_DEFAULT + P_DETACH + P_FOREGROUND + P_FULLSCREEN + P_MAXIMIZE + P_MINIMIZE + P_NOCLOSE + P_NOSESSION + P_NOWAIT + P_OVERLAY + P_PM + P_QUOTE + P_SESSION + P_TILDE + P_UNRELATED + P_WAIT + P_WINDOWED +); +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); + if ($! != 0) { + if ($! =~ /Invalid/) { + $AutoLoader::AUTOLOAD = $AUTOLOAD; + goto &AutoLoader::AUTOLOAD; + } + else { + ($pack,$file,$line) = caller; + die "Your vendor has not defined OS2::Process macro $constname, used at $file line $line. +"; + } + } + eval "sub $AUTOLOAD { $val }"; + goto &$AUTOLOAD; +} + +bootstrap OS2::Process; + +# Preloaded methods go here. + +# Autoload methods go after __END__, and are processed by the autosplit program. + +1; +__END__ + +=head1 NAME + +OS2::Process - exports constants for system() call on OS2. + +=head1 SYNOPSIS + + use OS2::Process; + $pid = system(P_PM+P_BACKGROUND, "epm.exe"); + +=head1 DESCRIPTION + +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. + +You can use either one of the process modes: + + P_WAIT (0) = wait until child terminates (default) + P_NOWAIT = do not wait until child terminates + P_SESSION = new session + P_DETACH = detached + P_PM = PM program + +and optionally add PM and session option bits: + + P_DEFAULT (0) = default + P_MINIMIZE = minimized + P_MAXIMIZE = maximized + P_FULLSCREEN = fullscreen (session only) + P_WINDOWED = windowed (session only) + + P_FOREGROUND = foreground (if running in foreground) + P_BACKGROUND = background + + P_NOCLOSE = don't close window on exit (session only) + + P_QUOTE = quote all arguments + P_TILDE = MKS argument passing convention + P_UNRELATED = do not kill child when father terminates + +=head1 AUTHOR + +Andreas Kaiser <ak@ananke.s.bawue.de>. + +=head1 SEE ALSO + +C<spawn*>() system calls. + +=cut diff --git a/os2/OS2/Process/Process.xs b/os2/OS2/Process/Process.xs new file mode 100644 index 0000000000..bdb2ece7a0 --- /dev/null +++ b/os2/OS2/Process/Process.xs @@ -0,0 +1,154 @@ +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" + +#include <process.h> + +static int +not_here(s) +char *s; +{ + croak("%s not implemented on this architecture", s); + return -1; +} + +static unsigned long +constant(name, arg) +char *name; +int arg; +{ + errno = 0; + if (name[0] == 'P' && name[1] == '_') { + if (strEQ(name, "P_BACKGROUND")) +#ifdef P_BACKGROUND + return P_BACKGROUND; +#else + goto not_there; +#endif + if (strEQ(name, "P_DEBUG")) +#ifdef P_DEBUG + return P_DEBUG; +#else + goto not_there; +#endif + if (strEQ(name, "P_DEFAULT")) +#ifdef P_DEFAULT + return P_DEFAULT; +#else + goto not_there; +#endif + if (strEQ(name, "P_DETACH")) +#ifdef P_DETACH + return P_DETACH; +#else + goto not_there; +#endif + if (strEQ(name, "P_FOREGROUND")) +#ifdef P_FOREGROUND + return P_FOREGROUND; +#else + goto not_there; +#endif + if (strEQ(name, "P_FULLSCREEN")) +#ifdef P_FULLSCREEN + return P_FULLSCREEN; +#else + goto not_there; +#endif + if (strEQ(name, "P_MAXIMIZE")) +#ifdef P_MAXIMIZE + return P_MAXIMIZE; +#else + goto not_there; +#endif + if (strEQ(name, "P_MINIMIZE")) +#ifdef P_MINIMIZE + return P_MINIMIZE; +#else + goto not_there; +#endif + if (strEQ(name, "P_NOCLOSE")) +#ifdef P_NOCLOSE + return P_NOCLOSE; +#else + goto not_there; +#endif + if (strEQ(name, "P_NOSESSION")) +#ifdef P_NOSESSION + return P_NOSESSION; +#else + goto not_there; +#endif + if (strEQ(name, "P_NOWAIT")) +#ifdef P_NOWAIT + return P_NOWAIT; +#else + goto not_there; +#endif + if (strEQ(name, "P_OVERLAY")) +#ifdef P_OVERLAY + return P_OVERLAY; +#else + goto not_there; +#endif + if (strEQ(name, "P_PM")) +#ifdef P_PM + return P_PM; +#else + goto not_there; +#endif + if (strEQ(name, "P_QUOTE")) +#ifdef P_QUOTE + return P_QUOTE; +#else + goto not_there; +#endif + if (strEQ(name, "P_SESSION")) +#ifdef P_SESSION + return P_SESSION; +#else + goto not_there; +#endif + if (strEQ(name, "P_TILDE")) +#ifdef P_TILDE + return P_TILDE; +#else + goto not_there; +#endif + if (strEQ(name, "P_UNRELATED")) +#ifdef P_UNRELATED + return P_UNRELATED; +#else + goto not_there; +#endif + if (strEQ(name, "P_WAIT")) +#ifdef P_WAIT + return P_WAIT; +#else + goto not_there; +#endif + if (strEQ(name, "P_WINDOWED")) +#ifdef P_WINDOWED + return P_WINDOWED; +#else + goto not_there; +#endif + } + + errno = EINVAL; + return 0; + +not_there: + errno = ENOENT; + return 0; +} + + +MODULE = OS2::Process PACKAGE = OS2::Process + + +unsigned long +constant(name,arg) + char * name + int arg + diff --git a/os2/OS2/REXX/Changes b/os2/OS2/REXX/Changes new file mode 100644 index 0000000000..46b38ef46c --- /dev/null +++ b/os2/OS2/REXX/Changes @@ -0,0 +1,4 @@ +0.2: + After fixpak17 a lot of other places have mismatched lengths +returned in the REXXPool interface. + Also drop does not work on stems any more. diff --git a/os2/OS2/REXX/MANIFEST b/os2/OS2/REXX/MANIFEST new file mode 100644 index 0000000000..4ac81492e4 --- /dev/null +++ b/os2/OS2/REXX/MANIFEST @@ -0,0 +1,14 @@ +Changes +MANIFEST +Makefile.PL +REXX.pm +REXX.xs +t/rx_cmprt.t +t/rx_dllld.t +t/rx_objcall.t +t/rx_sql.test +t/rx_tiesql.test +t/rx_tievar.t +t/rx_tieydb.t +t/rx_varset.t +t/rx_vrexx.t diff --git a/os2/OS2/REXX/Makefile.PL b/os2/OS2/REXX/Makefile.PL new file mode 100644 index 0000000000..07f6cc67ea --- /dev/null +++ b/os2/OS2/REXX/Makefile.PL @@ -0,0 +1,7 @@ +use ExtUtils::MakeMaker; + +WriteMakefile( + NAME => 'OS2::REXX', + VERSION => '0.2', + XSPROTOARG => '-noprototypes', +); diff --git a/os2/OS2/REXX/REXX.pm b/os2/OS2/REXX/REXX.pm new file mode 100644 index 0000000000..78e0cf917d --- /dev/null +++ b/os2/OS2/REXX/REXX.pm @@ -0,0 +1,387 @@ +package OS2::REXX; + +use Carp; +require Exporter; +require DynaLoader; +@ISA = qw(Exporter DynaLoader); +# Items to export into callers namespace by default +# (move infrequently used names to @EXPORT_OK below) +@EXPORT = qw(REXX_call REXX_eval REXX_eval_with); +# Other items we are prepared to export if requested +@EXPORT_OK = qw(drop); + +sub AUTOLOAD { + $AUTOLOAD =~ /^OS2::REXX::.+::(.+)$/ + or confess("Undefined subroutine &$AUTOLOAD called"); + return undef if $1 eq "DESTROY"; + $_[0]->find($1) + or confess("Can't find entry '$1' to DLL '$_[0]->{File}'"); + goto &$AUTOLOAD; +} + +@libs = split(/;/, $ENV{'PERL5REXX'} || $ENV{'PERLREXX'} || $ENV{'LIBPATH'} || $ENV{'PATH'}); +%dlls = (); + +bootstrap OS2::REXX; + +# Preloaded methods go here. Autoload methods go after __END__, and are +# processed by the autosplit program. + +# Cannot autoload, the autoloader is used for the REXX functions. + +sub load +{ + confess 'Usage: load OS2::REXX <file> [<dirs>]' unless $#_ >= 1; + my ($class, $file, @where) = (@_, @libs); + return $dlls{$file} if $dlls{$file}; + my $handle; + foreach (@where) { + $handle = DynaLoader::dl_load_file("$_/$file.dll"); + last if $handle; + } + return undef unless $handle; + eval "package OS2::REXX::$file; \@ISA = ('OS2::REXX');" + . "sub AUTOLOAD {" + . " \$OS2::REXX::AUTOLOAD = \$AUTOLOAD;" + . " goto &OS2::REXX::AUTOLOAD;" + . "} 1;" or die "eval package $@"; + return $dlls{$file} = bless {Handle => $handle, File => $file, Queue => 'SESSION' }, "OS2::REXX::$file"; +} + +sub find +{ + my $self = shift; + my $file = $self->{File}; + my $handle = $self->{Handle}; + my $prefix = exists($self->{Prefix}) ? $self->{Prefix} : ""; + my $queue = $self->{Queue}; + foreach (@_) { + my $name = "OS2::REXX::${file}::$_"; + next if defined(&$name); + my $addr = DynaLoader::dl_find_symbol($handle, uc $prefix.$_) + || DynaLoader::dl_find_symbol($handle, $prefix.$_) + or return 0; + eval "package OS2::REXX::$file; sub $_". + "{ shift; OS2::REXX::_call('$_', $addr, '$queue', \@_); }". + "1;" + or die "eval sub"; + } + return 1; +} + +sub prefix +{ + my $self = shift; + $self->{Prefix} = shift; +} + +sub queue +{ + my $self = shift; + $self->{Queue} = shift; +} + +sub drop +{ # Supposedly should drop anything with + # the given prefix. Unfortunately a + # loop is needed after fixpack17. +&OS2::REXX::_drop(@_); +} + +sub dropall +{ # Supposedly should drop anything with + # the given prefix. Unfortunately a + # loop is needed after fixpack17. + &OS2::REXX::_drop(@_); # Try to drop them all. + my $name; + for (@_) { + if (/\.$/) { + OS2::REXX::_fetch('DUMMY'); # reset REXX's first/next iterator + while (($name) = OS2::REXX::_next($_)) { + OS2::REXX::_drop($_ . $name); + } + } + } +} + +sub TIESCALAR +{ + my ($obj, $name) = @_; + $name =~ s/^[\w!?]+/\U$&\E/; + return bless \$name, OS2::REXX::_SCALAR; +} + +sub TIEARRAY +{ + my ($obj, $name) = @_; + $name =~ s/^[\w!?]+/\U$&\E/; + return bless [$name, 0], OS2::REXX::_ARRAY; +} + +sub TIEHASH +{ + my ($obj, $name) = @_; + $name =~ s/^[\w!?]+/\U$&\E/; + return bless {Stem => $name}, OS2::REXX::_HASH; +} + +############################################################################# +package OS2::REXX::_SCALAR; + +sub FETCH +{ + return OS2::REXX::_fetch(${$_[0]}); +} + +sub STORE +{ + return OS2::REXX::_set(${$_[0]}, $_[1]); +} + +sub DESTROY +{ + return OS2::REXX::_drop(${$_[0]}); +} + +############################################################################# +package OS2::REXX::_ARRAY; + +sub FETCH +{ + $_[0]->[1] = $_[1] if $_[1] > $_[0]->[1]; + return OS2::REXX::_fetch($_[0]->[0].'.'.(0+$_[1])); +} + +sub STORE +{ + $_[0]->[1] = $_[1] if $_[1] > $_[0]->[1]; + return OS2::REXX::_set($_[0]->[0].'.'.(0+$_[1]), $_[2]); +} + +############################################################################# +package OS2::REXX::_HASH; + +require Tie::Hash; +@ISA = ('Tie::Hash'); + +sub FIRSTKEY +{ + my ($self) = @_; + my $stem = $self->{Stem}; + + delete $self->{List} if exists $self->{List}; + + my @list = (); + my ($name, $value); + OS2::REXX::_fetch('DUMMY'); # reset REXX's first/next iterator + while (($name) = OS2::REXX::_next($stem)) { + push @list, $name; + } + my $key = pop @list; + + $self->{List} = \@list; + return $key; +} + +sub NEXTKEY +{ + return pop @{$_[0]->{List}}; +} + +sub EXISTS +{ + return defined OS2::REXX::_fetch($_[0]->{Stem}.$_[1]); +} + +sub FETCH +{ + return OS2::REXX::_fetch($_[0]->{Stem}.$_[1]); +} + +sub STORE +{ + return OS2::REXX::_set($_[0]->{Stem}.$_[1], $_[2]); +} + +sub DELETE +{ + OS2::REXX::_drop($_[0]->{Stem}.$_[1]); +} + +############################################################################# +package OS2::REXX; + +1; +__END__ + +=head1 NAME + +OS2::REXX - access to DLLs with REXX calling convention and REXX runtime. + +=head2 NOTE + +By default, the REXX variable pool is not available, neither +to Perl, nor to external REXX functions. To enable it, you need to put +your code inside C<REXX_call> function. REXX functions which do not use +variables may be usable even without C<REXX_call> though. + +=head1 SYNOPSIS + + use OS2::REXX; + $ydb = load OS2::REXX "ydbautil" or die "Cannot load: $!"; + @pid = $ydb->RxProcId(); + REXX_call { + tie $s, OS2::REXX, "TEST"; + $s = 1; + }; + +=head1 DESCRIPTION + +=head2 Load REXX DLL + + $dll = load OS2::REXX NAME [, WHERE]; + +NAME is DLL name, without path and extension. + +Directories are searched WHERE first (list of dirs), then environment +paths PERL5REXX, PERLREXX or, as last resort, PATH. + +The DLL is not unloaded when the variable dies. + +Returns DLL object reference, or undef on failure. + +=head2 Define function prefix: + + $dll->prefix(NAME); + +Define the prefix of external functions, prepended to the function +names used within your program, when looking for the entries in the +DLL. + +=head2 Example + + $dll = load OS2::REXX "RexxBase"; + $dll->prefix("RexxBase_"); + $dll->Init(); + +is the same as + + $dll = load OS2::REXX "RexxBase"; + $dll->RexxBase_Init(); + +=head2 Define queue: + + $dll->queue(NAME); + +Define the name of the REXX queue passed to all external +functions of this module. Defaults to "SESSION". + +Check for functions (optional): + + BOOL = $dll->find(NAME [, NAME [, ...]]); + +Returns true if all functions are available. + +=head2 Call external REXX function: + + $dll->function(arguments); + +Returns the return string if the return code is 0, else undef. +Dies with error message if the function is not available. + +=head1 Accessing REXX-runtime + +While calling functions with REXX signature does not require the presence +of the system REXX DLL, there are some actions which require REXX-runtime +present. Among them is the access to REXX variables by name. + +One enables REXX runtime by bracketing your code by + + REXX_call BLOCK; + +(trailing semicolon required!) or + + REXX_call \&subroutine_name; + +Inside such a call one has access to REXX variables (see below), and to + + REXX_eval EXPR; + REXX_eval_with EXPR, + subroutine_name_in_REXX => \&Perl_subroutine + +=head2 Bind scalar variable to REXX variable: + + tie $var, OS2::REXX, "NAME"; + +=head2 Bind array variable to REXX stem variable: + + tie @var, OS2::REXX, "NAME."; + +Only scalar operations work so far. No array assignments, no array +operations, ... FORGET IT. + +=head2 Bind hash array variable to REXX stem variable: + + tie %var, OS2::REXX, "NAME."; + +To access all visible REXX variables via hash array, bind to ""; + +No array assignments. No array operations, other than hash array +operations. Just like the *dbm based implementations. + +For the usual REXX stem variables, append a "." to the name, +as shown above. If the hash key is part of the stem name, for +example if you bind to "", you cannot use lower case in the stem +part of the key and it is subject to character set restrictions. + +=head2 Erase individual REXX variables (bound or not): + + OS2::REXX::drop("NAME" [, "NAME" [, ...]]); + +=head2 Erase REXX variables with given stem (bound or not): + + OS2::REXX::dropall("STEM" [, "STEM" [, ...]]); + +=head1 NOTES + +Note that while function and variable names are case insensitive in the +REXX language, function names exported by a DLL and the REXX variables +(as seen by Perl through the chosen API) are all case sensitive! + +Most REXX DLLs export function names all upper case, but there are a +few which export mixed case names (such as RxExtras). When trying to +find the entry point, both exact case and all upper case are searched. +If the DLL exports "RxNap", you have to specify the exact case, if it +exports "RXOPEN", you can use any case. + +To avoid interfering with subroutine names defined by Perl (DESTROY) +or used within the REXX module (prefix, find), it is best to use mixed +case and to avoid lowercase only or uppercase only names when calling +REXX functions. Be consistent. The same function written in different +ways results in different Perl stubs. + +There is no REXX interpolation on variable names, so the REXX variable +name TEST.ONE is not affected by some other REXX variable ONE. And it +is not the same variable as TEST.one! + +You cannot call REXX functions which are not exported by the DLL. +While most DLLs export all their functions, some, like RxFTP, export +only "...LoadFuncs", which registers the functions within REXX only. + +You cannot call 16-bit DLLs. The few interesting ones I found +(FTP,NETB,APPC) do not export their functions. + +I do not know whether the REXX API is reentrant with respect to +exceptions (signals) when the REXX top-level exception handler is +overridden. So unless you know better than I do, do not access REXX +variables (probably tied to Perl variables) or call REXX functions +which access REXX queues or REXX variables in signal handlers. + +See C<t/rx*.t> for examples. + +=head1 AUTHOR + +Andreas Kaiser ak@ananke.s.bawue.de, with additions by Ilya Zakharevich +ilya@math.ohio-state.edu. + +=cut diff --git a/os2/OS2/REXX/REXX.xs b/os2/OS2/REXX/REXX.xs new file mode 100644 index 0000000000..df7646c42e --- /dev/null +++ b/os2/OS2/REXX/REXX.xs @@ -0,0 +1,484 @@ +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" + +#define INCL_BASE +#define INCL_REXXSAA +#include <os2emx.h> + +#if 0 +#define INCL_REXXSAA +#pragma pack(1) +#define _Packed +#include <rexxsaa.h> +#pragma pack() +#endif + +extern ULONG _emx_exception ( EXCEPTIONREPORTRECORD *, + EXCEPTIONREGISTRATIONRECORD *, + CONTEXTRECORD *, + void *); + +static RXSTRING * strs; +static int nstrs; +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(PSZ name, ULONG argc, PRXSTRING argv, PSZ queue, PRXSTRING ret); + +#if 1 + #define Set RXSHV_SET + #define Fetch RXSHV_FETCH + #define Drop RXSHV_DROPV +#else + #define Set RXSHV_SYSET + #define Fetch RXSHV_SYFET + #define Drop RXSHV_SYDRO +#endif + +static long incompartment; + +static SV* +exec_in_REXX(char *cmd, char * handlerName, RexxFunctionHandler *handler) +{ + HMODULE hRexx, hRexxAPI; + BYTE buf[200]; + LONG APIENTRY (*pRexxStart) (LONG, PRXSTRING, PSZ, PRXSTRING, + PSZ, LONG, PRXSYSEXIT, PSHORT, PRXSTRING); + APIRET APIENTRY (*pRexxRegisterFunctionExe) (PSZ, + RexxFunctionHandler *); + APIRET APIENTRY (*pRexxDeregisterFunction) (PSZ); + RXSTRING args[1]; + RXSTRING inst[2]; + RXSTRING result; + USHORT retcode; + LONG rc; + SV *res; + + if (incompartment) die ("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)) { + die("REXX not available\n"); + } + + if (handlerName) + pRexxRegisterFunctionExe(handlerName, handler); + + 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, + &retcode, &result); + + incompartment = 0; + pRexxDeregisterFunction("StartPerl"); + DosFreeModule(hRexxAPI); + DosFreeModule(hRexx); + if (!RXNULLSTRING(result)) { + res = newSVpv(RXSTRPTR(result), RXSTRLEN(result)); + DosFreeMem(RXSTRPTR(result)); + } else { + res = NEWSV(729,0); + } + if (rc || SvTRUE(GvSV(errgv))) { + if (SvTRUE(GvSV(errgv))) { + die ("Error inside perl function called from REXX compartment.\n%s", SvPV(GvSV(errgv), na)) ; + } + die ("REXX compartment returned non-zero status %li", rc); + } + + return res; +} + +static SV* exec_cv; + +static ULONG +PERLSTART(PSZ name, ULONG argc, PRXSTRING argv, PSZ queue, PRXSTRING ret) +{ + return PERLCALL(NULL, argc, argv, queue, ret); +} + +#define in_rexx_compartment() exec_in_REXX("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(cmd,name,PERLSTART)) +#define REXX_eval(cmd) REXX_eval_with(cmd,NULL,NULL) + +static ULONG +PERLCALL(PSZ name, ULONG argc, PRXSTRING argv, PSZ queue, PRXSTRING ret) +{ + EXCEPTIONREGISTRATIONRECORD xreg = { NULL, _emx_exception }; + int i, rc; + unsigned long len; + char *str; + char **arr; + dSP; + + DosSetExceptionHandler(&xreg); + + ENTER; + SAVETMPS; + PUSHMARK(sp); + +#if 0 + if (!my_perl) { + DosUnsetExceptionHandler(&xreg); + return 1; + } +#endif + + if (name) { + int ac = 0; + char **arr = alloca((argc + 1) * sizeof(char *)); + + for (i = 0; i < argc; ++i) + arr[ac++] = argv[i].strptr; + arr[ac] = NULL; + + rc = perl_call_argv(name, G_SCALAR | G_EVAL, arr); + } else if (exec_cv) { + SV *cv = exec_cv; + + exec_cv = NULL; + rc = perl_call_sv(cv, G_SCALAR | G_EVAL); + } else rc = -1; + + SPAGAIN; + + if (rc == 1 && SvOK(TOPs)) { + str = SvPVx(POPs, len); + if (len > 256) + if (DosAllocMem((PPVOID)&ret->strptr, len, PAG_READ|PAG_WRITE|PAG_COMMIT)) { + DosUnsetExceptionHandler(&xreg); + return 1; + } + memcpy(ret->strptr, str, len); + ret->strlength = len; + } + + PUTBACK ; + FREETMPS ; + LEAVE ; + + if (rc != 1) { + DosUnsetExceptionHandler(&xreg); + return 1; + } + + + DosUnsetExceptionHandler(&xreg); + return 0; +} + +static void +needstrs(int n) +{ + if (n > nstrs) { + if (strs) + free(strs); + nstrs = 2 * n; + strs = malloc(nstrs * sizeof(RXSTRING)); + } +} + +static void +needvars(int n) +{ + if (n > nvars) { + if (vars) + free(vars); + nvars = 2 * n; + vars = malloc(nvars * sizeof(SHVBLOCK)); + } +} + +static void +initialize(void) +{ + needstrs(8); + needvars(8); + trace = getenv("PERL_REXX_DEBUG"); +} + +static int +not_here(s) +char *s; +{ + croak("%s not implemented on this architecture", s); + return -1; +} + +static int +constant(name, arg) +char *name; +int arg; +{ + errno = EINVAL; + return 0; +} + + +MODULE = OS2::REXX PACKAGE = OS2::REXX + +BOOT: + initialize(); + +int +constant(name,arg) + char * name + int arg + +SV * +_call(name, address, queue="SESSION", ...) + char * name + void * address + char * queue + CODE: + { + ULONG rc; + int argc, i; + RXSTRING result; + UCHAR resbuf[256]; + RexxFunctionHandler *fcn = address; + argc = items-3; + needstrs(argc); + if (trace) + fprintf(stderr, "REXXCALL::_call name: '%s' args:", name); + for (i = 0; i < argc; ++i) { + STRLEN len; + char *ptr = SvPV(ST(3+i), len); + MAKERXSTRING(strs[i], ptr, len); + if (trace) + fprintf(stderr, " '%.*s'", len, ptr); + } + if (!*queue) + queue = "SESSION"; + if (trace) + fprintf(stderr, "\n"); + MAKERXSTRING(result, resbuf, sizeof resbuf); + rc = fcn(name, argc, strs, queue, &result); + if (trace) + fprintf(stderr, " rc=%X, result='%.*s'\n", rc, + result.strlength, result.strptr); + ST(0) = sv_newmortal(); + if (rc == 0) { + if (result.strptr) + sv_setpvn(ST(0), result.strptr, result.strlength); + else + sv_setpvn(ST(0), "", 0); + } + if (result.strptr && result.strptr != resbuf) + DosFreeMem(result.strptr); + } + +int +_set(name,value,...) + char * name + char * value + CODE: + { + int i; + int n = (items + 1) / 2; + ULONG rc; + needvars(n); + if (trace) + fprintf(stderr, "REXXCALL::_set"); + for (i = 0; i < n; ++i) { + SHVBLOCK * var = &vars[i]; + STRLEN namelen; + STRLEN valuelen; + name = SvPV(ST(2*i+0),namelen); + if (2*i+1 < items) { + value = SvPV(ST(2*i+1),valuelen); + } + else { + value = ""; + valuelen = 0; + } + var->shvcode = RXSHV_SET; + var->shvnext = &vars[i+1]; + var->shvnamelen = namelen; + var->shvvaluelen = valuelen; + MAKERXSTRING(var->shvname, name, namelen); + MAKERXSTRING(var->shvvalue, value, valuelen); + if (trace) + fprintf(stderr, " %.*s='%.*s'", + var->shvname.strlength, var->shvname.strptr, + var->shvvalue.strlength, var->shvvalue.strptr); + } + if (trace) + fprintf(stderr, "\n"); + vars[n-1].shvnext = NULL; + rc = RexxVariablePool(vars); + if (trace) + fprintf(stderr, " rc=%X\n", rc); + RETVAL = (rc & ~RXSHV_NEWV) ? FALSE : TRUE; + } + OUTPUT: + RETVAL + +void +_fetch(name, ...) + char * name + PPCODE: + { + int i; + ULONG rc; + EXTEND(sp, items); + needvars(items); + if (trace) + fprintf(stderr, "REXXCALL::_fetch"); + for (i = 0; i < items; ++i) { + SHVBLOCK * var = &vars[i]; + STRLEN namelen; + name = SvPV(ST(i),namelen); + var->shvcode = RXSHV_FETCH; + var->shvnext = &vars[i+1]; + var->shvnamelen = namelen; + var->shvvaluelen = 0; + MAKERXSTRING(var->shvname, name, namelen); + MAKERXSTRING(var->shvvalue, NULL, 0); + if (trace) + fprintf(stderr, " '%s'", name); + } + if (trace) + fprintf(stderr, "\n"); + vars[items-1].shvnext = NULL; + rc = RexxVariablePool(vars); + if (!(rc & ~RXSHV_NEWV)) { + for (i = 0; i < items; ++i) { + int namelen; + SHVBLOCK * var = &vars[i]; + /* returned lengths appear to be swapped */ + /* but beware of "future bug fixes" */ + namelen = var->shvvalue.strlength; /* should be */ + if (var->shvvaluelen < var->shvvalue.strlength) + namelen = var->shvvaluelen; /* is */ + if (trace) + fprintf(stderr, " %.*s='%.*s'\n", + var->shvname.strlength, var->shvname.strptr, + namelen, var->shvvalue.strptr); + if (var->shvret & RXSHV_NEWV || !var->shvvalue.strptr) + PUSHs(&sv_undef); + else + PUSHs(sv_2mortal(newSVpv(var->shvvalue.strptr, + namelen))); + } + } else { + if (trace) + fprintf(stderr, " rc=%X\n", rc); + } + } + +void +_next(stem) + char * stem + PPCODE: + { + SHVBLOCK sv; + BYTE name[4096]; + ULONG rc; + int len = strlen(stem), namelen, valuelen; + if (trace) + fprintf(stderr, "REXXCALL::_next stem='%s'\n", stem); + sv.shvcode = RXSHV_NEXTV; + sv.shvnext = NULL; + MAKERXSTRING(sv.shvvalue, NULL, 0); + do { + sv.shvnamelen = sizeof name; + sv.shvvaluelen = 0; + MAKERXSTRING(sv.shvname, name, sizeof name); + if (sv.shvvalue.strptr) { + DosFreeMem(sv.shvvalue.strptr); + MAKERXSTRING(sv.shvvalue, NULL, 0); + } + rc = RexxVariablePool(&sv); + } while (!rc && memcmp(stem, sv.shvname.strptr, len) != 0); + if (!rc) { + EXTEND(sp, 2); + /* returned lengths appear to be swapped */ + /* but beware of "future bug fixes" */ + namelen = sv.shvname.strlength; /* should be */ + if (sv.shvnamelen < sv.shvname.strlength) + namelen = sv.shvnamelen; /* is */ + valuelen = sv.shvvalue.strlength; /* should be */ + if (sv.shvvaluelen < sv.shvvalue.strlength) + valuelen = sv.shvvaluelen; /* is */ + if (trace) + fprintf(stderr, " %.*s='%.*s'\n", + namelen, sv.shvname.strptr, + valuelen, sv.shvvalue.strptr); + PUSHs(sv_2mortal(newSVpv(sv.shvname.strptr+len, namelen-len))); + if (sv.shvvalue.strptr) { + PUSHs(sv_2mortal(newSVpv(sv.shvvalue.strptr, valuelen))); + DosFreeMem(sv.shvvalue.strptr); + } else + PUSHs(&sv_undef); + } else if (rc != RXSHV_LVAR) { + die("Error %i when in _next", rc); + } else { + if (trace) + fprintf(stderr, " rc=%X\n", rc); + } + } + +int +_drop(name,...) + char * name + CODE: + { + int i; + needvars(items); + for (i = 0; i < items; ++i) { + SHVBLOCK * var = &vars[i]; + STRLEN namelen; + name = SvPV(ST(i),namelen); + var->shvcode = RXSHV_DROPV; + var->shvnext = &vars[i+1]; + var->shvnamelen = namelen; + var->shvvaluelen = 0; + MAKERXSTRING(var->shvname, name, var->shvnamelen); + MAKERXSTRING(var->shvvalue, NULL, 0); + } + vars[items-1].shvnext = NULL; + RETVAL = (RexxVariablePool(vars) & ~RXSHV_NEWV) ? FALSE : TRUE; + } + OUTPUT: + RETVAL + +int +_register(name) + char * name + CODE: + RETVAL = RexxRegisterFunctionExe(name, PERLCALL); + OUTPUT: + RETVAL + +SV* +REXX_call(cv) + SV *cv + PROTOTYPE: & + +SV* +REXX_eval(cmd) + char *cmd + +SV* +REXX_eval_with(cmd,name,cv) + char *cmd + char *name + SV *cv diff --git a/os2/OS2/REXX/t/rx_cmprt.t b/os2/OS2/REXX/t/rx_cmprt.t new file mode 100644 index 0000000000..a73e43e36e --- /dev/null +++ b/os2/OS2/REXX/t/rx_cmprt.t @@ -0,0 +1,40 @@ +BEGIN { + chdir 't' if -d 't/lib'; + @INC = '../lib' if -d 'lib'; + require Config; import Config; + if (-d 'lib' and $Config{'extensions'} !~ /\bOS2::REXX\b/) { + print "1..0\n"; + exit 0; + } +} + +use OS2::REXX; + +$| = 1; # Otherwise data from REXX may come first + +print "1..13\n"; + +$n = 1; +sub do_me { + print "ok $n\n"; + "OK"; +} + +@res = REXX_call(\&do_me); +print "ok 2\n"; +@res == 1 ? print "ok 3\n" : print "not ok 3\n"; +$res[0] eq "OK" ? print "ok 4\n" : print "not ok 4\n# `$res[0]'\n"; + +# Try again +$n = 5; +@res = REXX_call(\&do_me); +print "ok 6\n"; +@res == 1 ? print "ok 7\n" : print "not ok 7\n"; +$res[0] eq "OK" ? print "ok 8\n" : print "not ok 8\n# `$res[0]'\n"; + +REXX_call { print "ok 9\n" }; +REXX_eval 'say "ok 10"'; +# Try again +REXX_eval 'say "ok 11"'; +print "ok 12\n" if REXX_eval("return 2 + 3") eq 5; +REXX_eval_with 'say myfunc()', myfunc => sub {"ok 13"}; diff --git a/os2/OS2/REXX/t/rx_dllld.t b/os2/OS2/REXX/t/rx_dllld.t new file mode 100644 index 0000000000..317743f3cb --- /dev/null +++ b/os2/OS2/REXX/t/rx_dllld.t @@ -0,0 +1,36 @@ +BEGIN { + chdir 't' if -d 't/lib'; + @INC = '../lib' if -d 'lib'; + require Config; import Config; + if (-d 'lib' and $Config{'extensions'} !~ /\bOS2::REXX\b/) { + print "1..0\n"; + exit 0; + } +} + +use OS2::REXX; + +$path = $ENV{LIBPATH} || $ENV{PATH} or die; +foreach $dir (split(';', $path)) { + next unless -f "$dir/YDBAUTIL.DLL"; + $found = "$dir/YDBAUTIL.DLL"; + last; +} +$found or die "1..0\n#Cannot find YDBAUTIL.DLL\n"; + +print "1..5\n"; + +$module = DynaLoader::dl_load_file($found) or die "not ok 1\n# load\n"; +print "ok 1\n"; + +$address = DynaLoader::dl_find_symbol($module, "RXPROCID") + or die "not ok 2\n# find\n"; +print "ok 2\n"; + +$result = OS2::REXX::_call("RxProcId", $address) or die "not ok 3\n# REXX"; +print "ok 3\n"; + +($pid, $ppid, $ssid) = split(/\s+/, $result); +$pid == $$ ? print "ok 4\n" : print "not ok 4\n# pid\n"; +$ssid == 1 ? print "ok 5\n" : print "not ok 5\n# pid\n"; +print "# pid=$pid, ppid=$ppid, ssid=$ssid\n"; diff --git a/os2/OS2/REXX/t/rx_objcall.t b/os2/OS2/REXX/t/rx_objcall.t new file mode 100644 index 0000000000..b4f04c308a --- /dev/null +++ b/os2/OS2/REXX/t/rx_objcall.t @@ -0,0 +1,33 @@ +BEGIN { + chdir 't' if -d 't/lib'; + @INC = '../lib' if -d 'lib'; + require Config; import Config; + if (-d 'lib' and $Config{'extensions'} !~ /\bOS2::REXX\b/) { + print "1..0\n"; + exit 0; + } +} + +use OS2::REXX; + +# +# DLL +# +$ydba = load OS2::REXX "ydbautil" or die "1..0\n# load\n"; +print "1..5\n", "ok 1\n"; + +# +# function +# +@pid = $ydba->RxProcId(); +@pid == 1 ? print "ok 2\n" : print "not ok 2\n"; +@res = split " ", $pid[0]; +print "ok 3\n" if $res[0] == $$; +@pid = $ydba->RxProcId(); +@res = split " ", $pid[0]; +print "ok 4\n" if $res[0] == $$; +print "# @pid\n"; + +eval { $ydba->nixda(); }; +print "ok 5\n" if $@ =~ /^Can't find entry 'nixda\'/; + diff --git a/os2/OS2/REXX/t/rx_sql.test b/os2/OS2/REXX/t/rx_sql.test new file mode 100644 index 0000000000..4f984250a3 --- /dev/null +++ b/os2/OS2/REXX/t/rx_sql.test @@ -0,0 +1,97 @@ +BEGIN { + chdir 't' if -d 't/lib'; + @INC = '../lib'; + require Config; import Config; + if ($Config{'extensions'} !~ /\bOS2::REXX\b/) { + print "1..0\n"; + exit 0; + } +} + +use OS2::REXX; + +sub stmt +{ + my ($s) = @_; + $s =~ s/\s*\n\s*/ /g; + $s =~ s/^\s+//; + $s =~ s/\s+$//; + return $s; +} + +sub sqlcode +{ + OS2::REXX::_fetch("SQLCA.SQLCODE"); +} + +sub sqlstate +{ + OS2::REXX::_fetch("SQLCA.SQLSTATE"); +} + +sub sql +{ + my ($stmt) = stmt(@_); + return 0 if OS2::REXX::_call("sqlexec", $sqlexec, "", $stmt); + return sqlcode() >= 0; +} + +sub dbs +{ + my ($stmt) = stmt(@_); + return 0 if OS2::REXX::_call("sqldbs", $sqldbs, "", $stmt); + return sqlcode() >= 0; +} + +sub error +{ + my ($where) = @_; + print "ERROR in $where: sqlcode=", sqlcode(), " sqlstate=", sqlstate(), "\n"; + dbs("GET MESSAGE INTO :MSG LINEWIDTH 75"); + my $msg = OS2::REXX::_fetch("MSG"); + print "\n", $msg; + exit 1; +} + +REXX_call { + + $sqlar = DynaLoader::dl_load_file("h:/sqllib/dll/sqlar.dll") or die "load"; + $sqldbs = DynaLoader::dl_find_symbol($sqlar, "SQLDBS") or die "find sqldbs"; + $sqlexec = DynaLoader::dl_find_symbol($sqlar, "SQLEXEC") or die "find sqlexec"; + + sql(<<) or error("connect"); + CONNECT TO sample IN SHARE MODE + + OS2::REXX::_set("STMT" => stmt(<<)); + SELECT name FROM sysibm.systables + + sql(<<) or error("prepare"); + PREPARE s1 FROM :stmt + + sql(<<) or error("declare"); + DECLARE c1 CURSOR FOR s1 + + sql(<<) or error("open"); + OPEN c1 + + while (1) { + sql(<<) or error("fetch"); + FETCH c1 INTO :name + + last if sqlcode() == 100; + + print "Table name is ", OS2::REXX::_fetch("NAME"), "\n"; + } + + sql(<<) or error("close"); + CLOSE c1 + + sql(<<) or error("rollback"); + ROLLBACK + + sql(<<) or error("disconnect"); + CONNECT RESET + +}; + +exit 0; diff --git a/os2/OS2/REXX/t/rx_tiesql.test b/os2/OS2/REXX/t/rx_tiesql.test new file mode 100644 index 0000000000..2947516755 --- /dev/null +++ b/os2/OS2/REXX/t/rx_tiesql.test @@ -0,0 +1,86 @@ +BEGIN { + chdir 't' if -d 't/lib'; + @INC = '../lib'; + require Config; import Config; + if ($Config{'extensions'} !~ /\bOS2::REXX\b/) { + print "1..0\n"; + exit 0; + } +} + +#extproc perl5 -Rx +#! perl + +use REXX; + +$db2 = load REXX "sqlar" or die "load"; +tie $sqlcode, REXX, "SQLCA.SQLCODE"; +tie $sqlstate, REXX, "SQLCA.SQLSTATE"; +tie %rexx, REXX, ""; + +sub stmt +{ + my ($s) = @_; + $s =~ s/\s*\n\s*/ /g; + $s =~ s/^\s+//; + $s =~ s/\s+$//; + return $s; +} + +sub sql +{ + my ($stmt) = stmt(@_); + return 0 if $db2->SqlExec($stmt); + return $sqlcode >= 0; +} + +sub dbs +{ + my ($stmt) = stmt(@_); + return 0 if $db2->SqlDBS($stmt); + return $sqlcode >= 0; +} + +sub error +{ + my ($where) = @_; + print "ERROR in $where: sqlcode=$sqlcode, sqlstate=$sqlstate\n"; + dbs("GET MESSAGE INTO :msg LINEWIDTH 75"); + print "\n", $rexx{'MSG'}; + exit 1; +} + +sql(<<) or error("connect"); + CONNECT TO sample IN SHARE MODE + +$rexx{'STMT'} = stmt(<<); + SELECT name FROM sysibm.systables + +sql(<<) or error("prepare"); + PREPARE s1 FROM :stmt + +sql(<<) or error("declare"); + DECLARE c1 CURSOR FOR s1 + +sql(<<) or error("open"); + OPEN c1 + +while (1) { + sql(<<) or error("fetch"); + FETCH c1 INTO :name + + last if $sqlcode == 100; + + print "Table name is $rexx{'NAME'}\n"; +} + +sql(<<) or error("close"); + CLOSE c1 + +sql(<<) or error("rollback"); + ROLLBACK + +sql(<<) or error("disconnect"); + CONNECT RESET + +exit 0; diff --git a/os2/OS2/REXX/t/rx_tievar.t b/os2/OS2/REXX/t/rx_tievar.t new file mode 100644 index 0000000000..6132e23f80 --- /dev/null +++ b/os2/OS2/REXX/t/rx_tievar.t @@ -0,0 +1,88 @@ +BEGIN { + chdir 't' if -d 't/lib'; + @INC = '../lib' if -d 'lib'; + require Config; import Config; + if (-d 'lib' and $Config{'extensions'} !~ /\bOS2::REXX\b/) { + print "1..0\n"; + exit 0; + } +} + +use OS2::REXX; + +# +# DLL +# +load OS2::REXX "ydbautil" or die "1..0\n# load\n"; + +print "1..19\n"; + +REXX_call { + print "ok 1\n"; + + # + # scalar + # + tie $s, OS2::REXX, "TEST"; + print "ok 2\n"; + $s = 1; + print "ok 3\n" if $s eq 1; + print "not ok 3\n# `$s'\n" unless $s eq 1; + untie $s; + + # + # hash + # + + tie %all, OS2::REXX, ""; # all REXX vars + print "ok 4\n"; + + sub show { + # show all REXX vars + print "--@_--\n"; + foreach (keys %all) { + $v = $all{$_}; + print "$_ => $v\n"; + } + } + + sub check { + # check all REXX vars + my ($test, @arr) = @_; + my @rx; + foreach $key (sort keys %all) { push @rx, $key, $all{$key} } + if ("@rx" eq "@arr") {print "ok $test\n"} + else { print "not ok $test\n# expect `@arr', got `@rx'\n" } + } + + + tie %h, OS2::REXX, "TEST."; + print "ok 5\n"; + check(6); + + $h{"one"} = 1; + check(7, "TEST.one", 1); + + $h{"two"} = 2; + check(8, "TEST.one", 1, "TEST.two", 2); + + $h{"one"} = ""; + check(9, "TEST.one", "", "TEST.two", 2); + print "ok 10\n" if exists $h{"one"}; + print "ok 11\n" if exists $h{"two"}; + + delete $h{"one"}; + check(12, "TEST.two", 2); + print "ok 13\n" if not exists $h{"one"}; + print "ok 14\n" if exists $h{"two"}; + + OS2::REXX::dropall("TEST."); + print "ok 15\n"; + check(16); + print "ok 17\n" if not exists $h{"one"}; + print "ok 18\n" if not exists $h{"two"}; + + untie %h; + print "ok 19"; + +}; diff --git a/os2/OS2/REXX/t/rx_tieydb.t b/os2/OS2/REXX/t/rx_tieydb.t new file mode 100644 index 0000000000..8251051265 --- /dev/null +++ b/os2/OS2/REXX/t/rx_tieydb.t @@ -0,0 +1,31 @@ +BEGIN { + chdir 't' if -d 't/lib'; + @INC = '../lib' if -d 'lib'; + require Config; import Config; + if (-d 'lib' and $Config{'extensions'} !~ /\bOS2::REXX\b/) { + print "1..0\n"; + exit 0; + } +} + +use OS2::REXX; +$rx = load OS2::REXX "ydbautil" or die "1..0\n# load\n"; # from RXU17.ZIP +print "1..7\n", "ok 1\n"; + +$rx->prefix("Rx"); # implicit function prefix +print "ok 2\n"; + +REXX_call { + tie @pib, OS2::REXX, "IB.P"; # bind array to REXX stem variable + print "ok 3\n"; + tie %tib, OS2::REXX, "IB.T."; # bind associative array to REXX stem var + print "ok 4\n"; + + $rx->GetInfoBlocks("IB."); # call REXX function + print "ok 5\n"; + defined $pib[6] ? print "ok 6\n" : print "not ok 6\n# pib\n"; + defined $tib{7} && $tib{7} =~ /^\d+$/ ? print "ok 7\n" + : print "not ok 7\n# tib\n"; + print "# Process status is ", unpack("I", $pib[6]), + ", thread ordinal is $tib{7}\n"; +}; diff --git a/os2/OS2/REXX/t/rx_varset.t b/os2/OS2/REXX/t/rx_varset.t new file mode 100644 index 0000000000..9d4f3b2e56 --- /dev/null +++ b/os2/OS2/REXX/t/rx_varset.t @@ -0,0 +1,39 @@ +BEGIN { + chdir 't' if -d 't/lib'; + @INC = '../lib' if -d 'lib'; + require Config; import Config; + if (-d 'lib' and $Config{'extensions'} !~ /\bOS2::REXX\b/) { + print "1..0\n"; + exit 0; + } +} + +use OS2::REXX; + +print "1..9\n"; + +REXX_call { + OS2::REXX::_set("X" => sqrt(2)) and print "ok 1\n"; + $x = OS2::REXX::_fetch("X") and print "ok 2\n"; + if (abs($x - sqrt(2)) < 5e-15) { + print "ok 3\n"; + } else { print "not ok 3\n# sqrt(2) = @{[sqrt(2)]} != `$x'\n" } + OS2::REXX::_set("Y" => sqrt(3)) and print "ok 4\n"; + $i = 0; + $n = 4; + while (($name, $value) = OS2::REXX::_next("")) { + $i++; $n++; + if ($i <= 2 and $name eq "Y" ) { + if ($value eq sqrt(3)) { + print "ok $n\n"; + } else { + print "not ok $n\n# `$name' => `$value'\n" ; + } + } elsif ($i <= 2 and $name eq "X") { + print "ok $n\n" if $value eq sqrt(2); + } else { print "not ok 7\n# name `$name', value `$value'\n" } + } + print "ok 7\n" if $i == 2; + OS2::REXX::_drop("X") and print "ok 8\n"; + $x = OS2::REXX::_fetch("X") or print "ok 9\n"; +}; diff --git a/os2/OS2/REXX/t/rx_vrexx.t b/os2/OS2/REXX/t/rx_vrexx.t new file mode 100644 index 0000000000..a40749f55f --- /dev/null +++ b/os2/OS2/REXX/t/rx_vrexx.t @@ -0,0 +1,59 @@ +BEGIN { + chdir 't' if -d 't/lib'; + @INC = '../lib' if -d 'lib'; + require Config; import Config; + if (-d 'lib' and $Config{'extensions'} !~ /\bOS2::REXX\b/) { + print "1..0\n"; + exit 0; + } +} + +use OS2::REXX; + +$name = "VREXX"; +$path = $ENV{LIBPATH} || $ENV{PATH} or die; +foreach $dir (split(';', $path)) { + next unless -f "$dir/$name.DLL"; + $found = "$dir/$name.DLL"; + print "# found at `$found'\n"; + last; +} +$found or die "1..0\n#Cannot find $name.DLL\n"; + +print "1..10\n"; + +REXX_call { + $vrexx = DynaLoader::dl_load_file($found) or die "not ok 1\n# load\n"; + print "ok 1\n"; + $vinit = DynaLoader::dl_find_symbol($vrexx, "VINIT") or die "find vinit"; + print "ok 2\n"; + $vexit = DynaLoader::dl_find_symbol($vrexx, "VEXIT") or die "find vexit"; + print "ok 3\n"; + $vmsgbox = DynaLoader::dl_find_symbol($vrexx, "VMSGBOX") or die "find vmsgbox"; + print "ok 4\n"; + $vversion= DynaLoader::dl_find_symbol($vrexx, "VGETVERSION") or die "find vgetversion"; + print "ok 5\n"; + + $result = OS2::REXX::_call("VInit", $vinit) or die "VInit"; + print "ok 6\n"; + print "# VInit: $result\n"; + + OS2::REXX::_set("MBOX.0" => 4, + "MBOX.1" => "Perl VREXX Access Test", + "MBOX.2" => "", + "MBOX.3" => "(C) Andreas Kaiser", + "MBOX.4" => "December 1994") + or die "set var"; + print "ok 7\n"; + + $result = OS2::REXX::_call("VGetVersion", $vversion) or die "VMsgBox"; + print "ok 8\n"; + print "# VGetVersion: $result\n"; + + $result = OS2::REXX::_call("VMsgBox", $vmsgbox, "", "Perl", "MBOX", 1) or die "VMsgBox"; + print "ok 9\n"; + print "# VMsgBox: $result\n"; + + OS2::REXX::_call("VExit", $vexit); + print "ok 10\n"; +}; diff --git a/os2/README b/os2/README new file mode 100644 index 0000000000..785a6098bb --- /dev/null +++ b/os2/README @@ -0,0 +1,814 @@ +Contents: + Notes on the patch + IMPORTANT NOTE + Target + Binary Install + Reading the docs + Notes on build on OS/2 + Compile summary + Tests which fail + Calls to external programs + OS/2 extensions + Report from the battlefield on 5.002_01 + +Notes on the patch: +~~~~~~~~~~~~~~~~~~~ +patches should be applied as + patch -p0 <..... +All the diff.* files and POSIX.mkfifo should be applied. + +Additional files are available on + ftp://ftp.math.ohio-state.edu/pub/users/ilya/os2 +including patched pdksh and gnumake, needed for build. + + <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< +IMPORTANT NOTE <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + +Note with the release 5.003_01 the dynamically loadable libraries +should be rebuilt. In particular, DLLs are now created with the names +which contain a checksum, thus allowing workaround for OS/2 scheme of +caching DLLs. + +In particular, it is VERY IMPORTANT to have a correct perl.dll on +LIBPATH during build, otherwise DLLs with wrong names will be +created. Or have a perl.dll with the same naming convention for DLLs +(hopefully, it should not change any time soon), or remove it from +LIBPATH, add . to LIBPATH, wait until the build of DynaLoader fails, +and then move the built DLL into LIBPATH. + +I also used this possibility to change perl linking type to -Zmt. It +means that Perl now uses multithreaded CRTDLL, so your extensions can +be multithreaded (note that the perl core is not thread-safe so far, +so make sure you access Perl from one thread only). In particular, it +is no longer needed to statically link X11_s.lib if you compile +Perl/Tk/XFree. + +This newer port includes + . numeric first argument to system(), see OS2::Process docs; + . modules OS2::Process, OS2::REXX, OS2::PrfDB, OS2::ExtAttrib. + . {get,set,end}*ent may work now (not checked) +(most of this merged from ak's port). + +Note that static build of OS2::ExtAttrib fails some tests! + +Target: +~~~~~~~ + +This is not supposed to make a perfect Perl on OS/2. This patch is +concerned only with perfect _build_ of Perl on OS/2. Some good +features from Andreas Kaiser port missed this port. However, most of +the features are available (possibly in different form). + +!!! Note that [gs]etpriority functions in this port are compatible +!!! with *nix, not with ak's port!!! + +The priorities are absolute, go from 32 to -95, lower is quickier. 0 +is default, + +Binary Install: +~~~~~~~~~~~~~~ +This version of perl allows binary installation on another site. There +are two possibilities: + a) sh.exe is in the directory with the same name as on machine +where perl was compiled (f:/bin here), and perl library is installed +into the same directory as the built target (f:/perllib); + b) One of the above conditions is not true. Perl may be +informed about location of sh.exe via PERL_SH_DRIVE or PERL_SH_DIR +(see below). To relocate the perl library, one can + b1) either use the usual PERLLIB environment variable - but +you should deduce yourself which components should be put there, say, +by doing + perl -de 0 + x \@INC + q +in the directory of the perl library. Another problem with this is +that a module is missing, then perl will try to scan the builtin +directories nevertheless. If perl was intended to be installed on +f:/perllib, but your f: is a CDROM, then you may have some trouble. + b2) Best: binary edit perl.dll and perl_.exe (using perl +itself as a binary editor) to fix the paths. Note that the new paths +should be better no longer than the old. + b3) More convinient: set PERLLIB_PREFIX environment +variable. It should contain two components, separated by whitespace +and/or semicolon `;'. The first component is translated to the second +one if it is + a prefix of + a component of + Perl library lookup path. +Say, if you install perllibrary into c:/lib/perl/ instead of +f:/perllib/, set it to + set PERLLIB_PREFIX=f:/perllib/;c:/lib/perl/ + +Reading the docs: +~~~~~~~~~~~~~~~~ +If your `man' is correctly installed, you should just add +x:/perllib/man directory to the end of MANPATH like this: + set MANPATH=c:/man;f:/perllib/man +After this you can access the docs like this: + man perlfunc + man 3 less + man ExtUtils.MakeMaker +Note that dot is used as package separator for package documentation, +and as usual, sometimes you need to give the section - 3 above - to +avoid shadowing by the less(1) manpage. + +Alternatively, you can build HTML docs by running + pod2html +in x:/perllib/lib/pod directory. + +Alternatively, you can build IPF source by running + pod2ipf > perl.ipf +in x:/perllib/lib/pod directory, and build (excellent! - best of perl +docs available!) .INF documentation by running + ipfc /inf perl.ipf +Move it on your BOOKSHELF path, and now you may inspect docs by + view perl +or + view perl keyword_to_see + +Alternatively you may pick up precompiled HTML and .INF docs from the +net, as usual, .INF is available on CPAN/.../os2/ilyaz. + +There are also _very_ good docs in TexInfo and Adobe PDF format. + +Notes on build on OS/2: +~~~~~~~~~~~~~~~~~~~~~~~ +a) Make sure your sort is not the broken OS/2 one, and that you have /tmp +on the build partition. Make sure that your pdksh.exe, make.exe and +db.lib are OK (look elsewhere in this file). + +b) when extracting perl5.*.tar.gz you need to extract perl5.*/Configure +separately, since by default perl5.001m/configure may overwrite it; + like this: + tar vzxf perl5.004.tar.gz --case-sensitive perl5.004/Configure +or + tar --case-sensitive -vzxf perl5.004.tar.gz perl5.004/Configure + +c) Necessary manual intervention when compiling on OS/2: + + Need to put perl.dll on LIBPATH after it is created. + +d) Compile summary: + ~~~~~~~~~~~~~~~ +!!! At the end of this README is independent description of the build +!!! process by Rocco Caputo. + +# Look for hints/os2.sh and correct what is different on your system +# I have rather spartan configuration. + + # Prefix means where to install: +sh Configure -des -D prefix=f:/perl5.005 + # Note that you need to have /tmp/ ready. + # + # Ignore the message about missing `ln', and about `c' option + # to tr. +make + # Will probably die after build of miniperl (unless you have DLL + # from previous compile). Need to move DLL where it belongs + # + # Somehow with 5.002b3 I needed to type another make after pod2man +make + # some warnings in POSIX.c +make test + # some tests fail, 9 or 10 on my system (see the list at end). + # + # before this you should create subdirs bin and lib in the + # prefix directory (f:/perl5.005 above): + # + # To run finer tests, cd t && perl harness +make install + +e) At the end of July 1996 GNU make was too buggy for compile. +The maintainer has the patch (for a year now) that make it possible to +compile perl. The binaries are included in + ftp://ftp.math.ohio-state.edu/pub/users/ilya/os2 +patches are available too. + +Note that the pdksh5.2.7 or later is required. + +!!!!!!!!!!!!!!!!! +If you see that some '/' became '\' in pdksh, you use an old pdksh! +Same with segfaults in Make 3.76 (?) - use my patched verions. +!!!!!!!!!!!!!!!!! + +f) As distributed the DB library db.a-db.lib is not suitable for +linking with -Zmt. A recompiled version must be available from my FTP +site in os2/db_mt.zip. + +!!!!!!!!!!!!!!!! +If you see: + 'errno' - unresolved external +it means you use a wrong db.lib. +!!!!!!!!!!!!!!!! + +Problems reported: + +a) one of the latest tr is broken, get an old one :-( + 1.11 works. (On compuserver?) +b) You need a perlglob.exe and link386. +c) Get rid of invalid perl.dll on your LIBPATH. + + +Send comments to ilya@math.ohio-state.edu. + +====================================================== +Requires 0.9b (well, provision are made to make it build under 0.9a6, +but they are not tested, please inform me on success). +(earlier than 0.9b ttyname was not present, it is hard to maintain this +difference automatically, though I try). +====================================================== + +Building with a.out style is supported by the `perl_' target of make. +Dynamic extensions are not possible with perl_.exe, since boot code +should return the retvalue on the Perl stack, the address of which is +not known to the extension. Moreover: The build process for `perl_' +DOES NOT KNOW about dependencies, so you should make sure that +anything is up-to-date, say, by doing + make perl.dll +first. + +The reason why compiling with a.out style executables leads to problems +with dynamic extensions is: + a) OS/2 does not export symbols from executables; + b) Thus if extension needs to import symbols from an application + the symbols for the application should reside in a .dll. + c) You cannot export data from a .dll compiled with a.out style. +On the other hand, aout-style compiled extension enjoys all the +(dis)advantages of fork(). + +====================================================== + +If you need to run PM code from perl, you may use PM mode executable +perl__.exe. It is subject to restrictions specific to PM programs: it +will close the VIO window the moment any PM call is performed. + +It is needed to run Perl/Tk (currently 7/96 - pre-alpha). + +====================================================== + +The reason why the executables are named perl_.exe and perl__.exe is +the following: Perl may parse #! lines in perl scripts to find out the +additional switches to enable. Thus there is a convention `What is a +perl executable - judging by name', and the above names conform to +this convention. + +====================================================== +Tests which fail +~~~~~~~~~~~~~~~~ +with OMF compile (fork works - and all the related +test - with A.OUT compile): + +io/fs.t: 2-5, 7-11, 18 as they should. +io/pipe: all, since open("|-") is not working (works with perl_.exe). +lib/"all the dbm".t: 1 test should fail (file permission). +lib/io_pipe io_sock, as they should: use fork. +op/fork all fail, as they should (except with perl_.exe) +op/stat 3 20 35 as they should, 39 (-t on /dev/null) ???? Sometimes 4 +- timing problem ???? + +Sometimes I have seen segfault in socket ????, only if run with Testing tools. + +A lot of `bad free'... in databases, bug in DB confirmed on other +platforms. You may disable it by setting PERL_BADFREE environment variable +to 0. + +Here is my result with OMF: + +Test Status Wstat Total Fail Success List of failed +------------------------------------------------------------------------------ +io/fs.t 22 10 45.45% 2-5, 7-11, 18 +io/pipe.t 1 256 8 ?? % ?? +lib/anydbm.t 12 1 8.33% 2 +lib/db-btree.t 86 1 1.16% 20 +lib/db-hash.t 43 1 2.33% 16 +lib/db-recno.t 35 1 2.86% 18 +lib/io_pipe.t 2 512 6 ?? % ?? +lib/io_sock.t 255 65280 5 ?? % ?? +lib/sdbm.t 12 1 8.33% 2 +op/exec.t 8 1 12.50% 5 +op/fork.t 255 65280 2 ?? % ?? +op/stat.t 56 4 7.14% 3, 20, 35, 39 +Failed 12/104 test scripts, 88.46% okay. 41/2224 subtests failed, 98.16% okay. + +and with A.OUT: + +Test Status Wstat Total Fail Failed List of failed +------------------------------------------------------------------------------ +io/fs.t 22 10 45.45% 2-5, 7-11, 18 +lib/anydbm.t 12 1 8.33% 2 +lib/db-btree.t 86 1 1.16% 20 +lib/db-hash.t 43 1 2.33% 16 +lib/db-recno.t 35 1 2.86% 18 +lib/sdbm.t 12 1 8.33% 2 +op/exec.t 8 1 12.50% 5 +op/stat.t 56 4 7.14% 3, 20, 35, 39 +Failed 8/104 test scripts, 92.31% okay. 20/2224 subtests failed, 99.10% okay. + +Note that op/exec.5 fail because I do not have /bin/sh on this drive. + +With newer configs I could not reproduce most the crashes. However, +after fixpak17 REXX variables acquire a trailing '\0' at end when go +through the variable pool (even if they had one), thus making some +REXX tests fail. + +======================================================= + +Calls to external programs: +~~~~~~~~~~~~~~~~~~~~~~~~~~ +Due to a popular demand the perl external program calling has been +changed. _If_ perl needs to call an external program _via shell_, the +X:/bin/sh.exe will be called. The name of the shell is +overridable, as described below. + +Thus means that you need to pickup some copy of a sh.exe as well (I use one +from pdksh). The drive X: above is set up automatically during the +build, is settable in runtime from $ENV{PERL_SH_DRIVE}. Another way to +change it is to set $ENV{PERL_SH_DIR} to be the directory in which +sh.exe resides. + +Reasons: a consensus on perl5-porters was that perl should use one +non-overridable shell per platform. The obvious choices for OS/2 are cmd.exe +and sh.exe. Having perl build itself would be impossible with cmd.exe as +a shell, thus I picked up sh.exe. Thus assures almost 100% compatibility +with the scripts coming from *nix. + +Disadvantages: sh.exe calls external programs via fork/exec, and there is +_no_ functioning exec on OS/2. exec is emulated by EMX by asyncroneous call +while the caller waits for child completion (to pretend that pid did +not change). This means that 1 _extra_ copy of sh.exe is made active via +fork/exec, which may lead to some resources taken from the system. + +The long-term solution proposed on p5-p is to have a directive + use OS2::Cmd; +which will override system(), exec(), ``, and open(,' |'). With current +perl you may override only system(), readpipe() - the explicit version +of ``, and maybe exec(). The code will substitute a one-argument system +by CORE::system('cmd.exe', '/c', shift). + +If you have some working code for OS2::Cmd.pm, please send it to me, +I will include it into distribution. I have no need for such a module, so +cannot test it. + +=================================================== + +OS/2 extensions +~~~~~~~~~~~~~~~ +Since binaries cannot go into perl distribution, no extensions are +included. They are available in .../os2/ilyaz directory of CPAN, as +well as in my directory + ftp://ftp.math.ohio-state.edu/pub/users/ilya/os2 + +I include 3 extensions by Andread Kaiser, OS2::REXX, OS2::UPM, and OS2::FTP, +into my ftp directory, mirrored on CPAN. I made +some minor changes needed to compile them by standard tools. I cannot +test UPM and FTP, so I will appreciate your feedback. Other extensions +there are OS2::ExtAttribs, OS2::PrfDB for tied access to EAs and .INI +files - and maybe some other extensions at the time you read it. + +Note that OS2 perl defines 2 pseudo-extension functions +OS2::Copy::copy and DynaLoader::mod2fname. + +The -R switch of older perl is deprecated. If you need to call a REXX code +which needs access to variables, include the call into a REXX compartment +created by + REXX_call {...block...}; + +Two new functions are supported by REXX code, + REXX_eval 'string'; + REXX_eval_with 'string', REXX_function_name => \&perl_sub_reference; + +If you have some other extensions you want to share, send the code to +me. At least two are available: tied access to EA's, and tied access +to system databases. + +================================================================== +== == +== User report [my comments in brackets, IZ] == +== == +== A web page: http://www.shadow.net/~troc/os2perl.html == +== == +================================================================== + +Starting in x:/usr/src, using 4OS2/32 2.5 as the command interpreter on +OS/2 2.30 with FixPak-17. DAX is installed, but this shouldn't be a +factor. Drive X is a TVFS virtual drive pointing to several physical +HPFS drives. + +>>> Make sure that no copies or perl are currently running. Miniperl + may fail during the build because it will find an older version + of perl.dll loaded in memory. + + Close any running perl scripts. + Shut down anything that might run perl scripts, like cron. + `emxload -l` to check for loaded versions of perl. + `emxload -u perl.exe` to unload them. + +>>> Pre-load some common utilities: + + emxload -e sh.exe make.exe ls.exe tr.exe id.exe sed.exe + SET GCCLOAD=30 (number of minutes to hold the compiler) +[grep egrep fgrep cat rm uniq basename uniq sort - are not bad too.] + The theory is that it's faster to demand-load the development tools + from virtual memory than it is to re-load and re-link them all the + time. This is definitely true with my system because swapfile.dat + is on a faster drive than my development environment. + + ls, tr, and id represent the GNU file, text, and shell utilities. + These may not be needed, but it makes sure that their respective + DLLs are in memory. + +>>> Unpack the perl 5_002_01 archive onto an HPFS partition. + + tar vxzf perl5_002_01.tar-gz + cd perl5.002_01 + +[Do not forget to extract Configure as described above.] + +>>> Read the README, keeping a copy open in another session for reference. + + start /c /fg less os2/README + +>>> Apply the OS/2 patches included with 5.002_01, as per the README. + + for %m in (os2\diff.*) patch -p0 < %m + patch -p0 < os2\POSIX.mkfifo + +[The patch below is already applied.] + +>>> You may need to apply this patch if you plan to run a non-standard + Configure (that is, if you defy the README). This patch will ensure + that Makefile inherits the libraries specified during Configure. + People running standard perl builds can probably ignore this patch. + +*** os2\Makefile.SHs Mon Mar 25 02:05:00 1996 +--- os2\Makefile.SHs.new Fri May 24 10:37:10 1996 +*************** +*** 9,15 **** + emximp -o perl.imp perl5.def + + perl.dll: $(obj) perl5.def perl$(OBJ_EXT) +! $(LD) $(LDDLFLAGS) -o $@ perl$(OBJ_EXT) $(obj) -lsocket perl5.def + + perl5.def: perl.linkexp + echo "LIBRARY 'Perl' INITINSTANCE TERMINSTANCE" > $@ +--- 9,15 ---- + emximp -o perl.imp perl5.def + + perl.dll: $(obj) perl5.def perl$(OBJ_EXT) +! $(LD) $(LDDLFLAGS) -o $@ perl$(OBJ_EXT) $(obj) $(libs) perl5.def + + perl5.def: perl.linkexp + echo "LIBRARY 'Perl' INITINSTANCE TERMINSTANCE" > $@ +*************** +*** 49,55 **** + cat perl.exports perl.map | sort | uniq -d | sed -e 's/\w\+/ "\0"/' > perl.linkexp + + perl.map: $(obj) perl$(OBJ_EXT) miniperlmain$(OBJ_EXT) +! $(CC) $(LARGE) $(CLDFLAGS) $(CCDLFLAGS) -o dummy.exe miniperlmain$(OBJ_EXT) perl$(OBJ_EXT) $(obj) -lsocket -lm -Zmap -Zlinker /map + awk '{if ($$3 == "") print $$2}' <dummy.map | sort | uniq > perl.map + rm dummy.exe dummy.map + +--- 49,55 ---- + cat perl.exports perl.map | sort | uniq -d | sed -e 's/\w\+/ "\0"/' > perl.linkexp + + perl.map: $(obj) perl$(OBJ_EXT) miniperlmain$(OBJ_EXT) +! $(CC) $(LARGE) $(CLDFLAGS) $(CCDLFLAGS) -o dummy.exe miniperlmain$(OBJ_EXT) perl$(OBJ_EXT) $(obj) $(libs) -Zmap -Zlinker /map + awk '{if ($$3 == "") print $$2}' <dummy.map | sort | uniq > perl.map + rm dummy.exe dummy.map + +>>> Apply the patches from Ilya's perl5.002_01 binary distribution: + + touch os2/dlfcn.h os2/dl_os2.c + patch -p1 < f:\perllib\README.fix1 + +>>> Run Configure. Most people can run it by following the README: + + sh Configure -des -D prefix=f:/usr/local + + Advanced perl users (experienced C programmers, recommended) can run + the interactive Configure and answer the questions. When in doubt + about an answer, check the EMX headers and documentation. Pick the + default answer if that doesn't help: + + sh Configure + +[Yet more advanced users just specify the answers on the command line +of Configure, like I did with prefix.] + + Note: You may need to wrap an answer in quotes if it contains + spaces. For example, "-lsocket -lm". + + Note: If you want to add some options to a long default, you can + use $* to include the default in your answer: "$* -DDEBUGGING". + + Configure warnings and errors, and possible work-arounds: + + I don't know where 'ln' is.... + (ignored; OS/2 doesn't have a ln command) + + nm didn't seem to work right. Trying emxomfar instead... + (nothing to worry about) + + The recommended value for $d_shrplib on this machine was "define"! + (kept the recommended value: y) + + Directory f:/usr/lib/perl5/os2/5.00201/CORE doesn't exist. + (created the directory from another window with + \usr\bin\mkdir -p f:/usr/lib/perl5/os2/5.00201/CORE + and then answered: y. Your directory may look different.) + +[Ignore this as well, install script will create it for you.] + + The recommended value for $i_dlfcn on this machine was "define"! + (kept the recommended value: y) + + The recommended value for $d_fork on this machine was "undef"! + (kept the recommended value: y) + + Figuring out the flag used by open() for non-blocking I/O... + Seems like we can use O_NONBLOCK. + This seems to be used for informative purposes only. + The errors that follow this (including a SIGPIPE) don't seem + to affect perl at all. These were safely ignored. + + What pager is used on your system? [/usr/ucb/more] + Had to answer "/usr/bin/less.exe" because Configure wants a + leading / (unix full path). Need to edit config.sh later with + the real full path to the pager, including the drive letter. + +[Apparently this setting is never used, so it is safe to ignore it.] + + Hmm... F:/USR/BIN/sed: Unterminated `s' command + Perl built fine even with this error, so it seems safe to + ignore. + + Things I did different from the defaults. Most (if not all) of these + are optional changes. They're listed here to show how good Configure + is at detecting the system setup. + +[I add the options to put it on command line of Configure, see below.] + + Selected 'none' for the man1 location. + (I prefer the pod2html version.) +[-D man1dir=none] + Selected 'none' for the man3 location. + (I prefer the pod2html version.) +[-D man3dir=none] + Changed the hostname and domain. + (I wanted to override a dynamic PPP address. This only + matters if other people will be using your perl build.) +[-D myhostname=my_host_name -D mydomain=.foo.org] + Fixed the e-mail address. + (Put in a known working e-mail address. This only matters + if other people will be using your perl build.) +[-D cf_email=root@myhostname.uucp] + Added some directories to the library search path. +[-D "libpth=f:/emx/lib/st f:/emx/lib"] + Added -g to the optimizer/debugger flags. +[-D optimize=-g] + Added "-lgdbm -ldb -lcrypt -lbsd" to the additional libraries. +[ -D "libs=-lsocket -lcrypt -lgdbm" + the rest of libraries will not be used] + +>>> Advanced users may want to edit config.sh when prompted by Configure. + Most (all?) of these changes aren't really necessary: + + d_getprior='define' + d_setprior='define' + (getpriority and setpriority are included in os2.c, but + Configure doesn't know to look there.) +[fixed already] + pager='f:/usr/bin/less.exe' + (Correcting Configure's insistence on a leading slash.) + bin_sh='f:/usr/bin/sh.exe' + (If Configure detects sh.exe somewhere else first. Example: + it saw sh.exe at /bin/sh.exe on my TVFS drive, but I want + perl to look for it on the physical F drive.) + aout_ccflags='... existing flags... -DDEBUGGING' + aout_cppflags='... existing flags... -DDEBUGGING' + (If you want to include DEBUGGING for the aout version.) +[Do not do it, -D optimize=-g will automatically add these flags.] + +>>> Allow Configure to make the build scripts. + +>>> Allow Configure to run `make depend`. Ignore the following warning: + + perl.h:861: warning: `DEBUGGING_MSTATS' redefined +[corrected now] + +>>> Rename any existing perl.dll, preventing anything from loading it and + saving a known working copy in case something goes wrong: + + mv /usr/lib/perl.dll /usr/lib/ilya-perl.dll + +>>> Run `make`, and ignore the following warnings: + + perl.h:861: warning: `DEBUGGING_MSTATS' redefined +[corrected now] + invalid preprocessing directive name + emxomf warning: Cycle detected by make_type + LINK386 : warning L4071: application type not specified; assuming WINDOWCOMPAT + Warning (will try anyway): No library found for -lposix + Warning (will try anyway): No library found for -lcposix + POSIX.c:203: warning: `mkfifo' redefined + POSIX.c:4603: warning: assignment makes pointer from integer without a cast + +>>> If `make` dies while "Making DynaLoader (static)", you'll need to + put miniperl in the OS/2 paths. This step is only necessary if `make` + can't find miniperl: +[I would be interested if somebody confirmes this.] + + cp perl.dll /usr/lib (where /usr/lib is in your LIBPATH) + cp miniperl.exe /usr/bin (where /usr/bin is in your PATH) + make (ignore the errors in the previous step) + + This should run to completion. + +>>> Test the build: + + make test + + These tests fail: + + io/fs..........FAILED on test 2 + + "OS/2 is not unix". Test 2 checks the link() command, which + is not supported by OS/2. + + io/pipe........f:/usr/bin/sh.exe: -c requires an argument + f:/usr/bin/sh.exe: -c requires an argument + The Unsupported function fork function is unimplemented at + io/pipe.t line 26. + FAILED on test 1 + + More "OS/2 is not unix" errors. Read ahead to find out + why fork() fails. + + op/exec........FAILED on test 4 + + if (system "true") {print "not ok 4\n";} else \ + {print "ok 4\n";} + + This fails for me, but changing it to read like this works: + + if (system '\usr\bin\true.cmd') {print "not ok 4\n";} \ + else {print "ok 4\n";} + + So you can count this as another "OS/2 is not unix". + + op/fork........The Unsupported function fork function is \ + unimplemented at op/fork.t line 8. + FAILED on test 1 + + The dynamically-loaded version of perl currently doesn't + support fork(). This is a known behavior of EMX. + + op/magic....... + Process terminated by SIGINT + ok + + The test passed even with the SIGINT message. I don't + know why, but I won't argue. + + op/stat........ls: /dev: No such file or directory + f:/usr/bin/sh.exe: ln: not found + ls: perl: No such file or directory + FAILED on test 3 + + "OS/2 is not unix". We don't have the ln command. + + lib/anydbm.....Bad free() ignored at lib/anydbm.t line 51. + Bad free() ignored at lib/anydbm.t line 51. + Bad free() ignored at lib/anydbm.t line 51. + Bad free() ignored during global destruction. + Bad free() ignored during global destruction. + Bad free() ignored during global destruction. + FAILED on test 2 + + Test 2 looks at the file permissions for a database. "OS/2 + is not unix" so the permissions aren't exactly what this test + expects. + + lib/db-btree...Bad free() ignored at lib/db-btree.t line 109. + Bad free() ignored at lib/db-btree.t line 221. + Bad free() ignored at lib/db-btree.t line 337. + Bad free() ignored at lib/db-btree.t line 349. + Bad free() ignored at lib/db-btree.t line 349. + Bad free() ignored at lib/db-btree.t line 399. + Bad free() ignored at lib/db-btree.t line 400. + Bad free() ignored at lib/db-btree.t line 401. + FAILED on test 20 + + Another file permissions test fails. + + lib/db-hash....Bad free() ignored at lib/db-hash.t line 101. + Bad free() ignored at lib/db-hash.t line 101. + Bad free() ignored at lib/db-hash.t line 101. + Bad free() ignored at lib/db-hash.t line 239. + Bad free() ignored at lib/db-hash.t line 239. + Bad free() ignored at lib/db-hash.t line 239. + Bad free() ignored at lib/db-hash.t line 253. + Bad free() ignored at lib/db-hash.t line 253. + Bad free() ignored at lib/db-hash.t line 253. + FAILED on test 16 + + Another file permissions test fails. + + lib/db-recno...Bad free() ignored at lib/db-recno.t line 138. + Bad free() ignored at lib/db-recno.t line 138. + FAILED on test 18 + + Another file permissions test fails. + + lib/gdbm.......FAILED on test 2 + + Another file permissions test fails. + + lib/sdbm.......FAILED on test 2 + + Another file permissions test fails. + + Failed 11/94 tests, 88.30% okay. + + All of which are known differences with unix or documented + behaviors in EMX. I re-run the test with Ilya's version, + and the same tests fail. This new build is a success. +[Note that bad free() mentioned above are bugs in the Berkeley +DB. They just are more visible under OS/2 with perl free(), because of +"rigid" function name resolution. You may disable it by setting +PERL_BADFREE environment variable to 0. + To get finer tests, cd to ./t and run + perl harness +] + + (Actually, Ilya's perl release fails an extra test because I don't + have sed in f:\emx.add. This shows how important it is to configure + and build perl yourself instead of grabbing pre-built binaries.) +[Hmm, should not happen... There is no mentions of full_sed under ./t +directory...] + +>>> Cross your fingers and install it: + + make install + + Warnings encountered and workarounds presented.: + + WARNING: You've never run 'make test'!!! (Installing anyway.) + (Lies! All lies! At least it still installs.) + + WARNING: Can't find libperl*.dll* to install into \ + f:/usr/lib/perl5/os2/5.00201/CORE. (Installing other things anyway.) + (Safe to ignore. The important one, libperl.lib, gets copied.) + + Couldn't copy f:/usr/bin/perl5.00201.exe to f:/usr/bin/perl.exe: \ + No such file or directory + cp /usr/bin/perl5.00201.exe /usr/bin/perl.exe + + Couldn't copy f:/usr/bin/perl.exe to /usr/bin/perl.exe: No such \ + file or directory + (I think this one is safe to ignore since the two directories + point to the same place.) + +>>> Laugh maniacally because you just built and installed your own copy + of perl, with all the paths set "just so" and with whatever little + psychotic modifications you've always wanted but were afraid to add. + +----------------------------------------------------------------------------- + +Development tools and versions: + + EMX 0.9b with emxfix04 applied. + + `ls --version` reports: 'GNU file utilities 3.12' + `tr --version` reports: 'tr - GNU textutils 1.14' + `id --version` reports: 'id - GNU sh-utils 1.12' + + `sed --version` reports: 'GNU sed version 2.05' + `awk --version` reports: 'Gnu Awk (gawk) 2.15, patchlevel 6' + `grep --version` reports an illegal option and: 'GNU grep version 2.0' + (this includes egrep) + + `sort --version` reports: 'sort - GNU textutils 1.14' + `uniq --version` reports: 'uniq - GNU textutils 1.14' + `find --version` reports: 'GNU find version 4.1' + + KSH_VERSION='@(#)PD KSH v5.2.4 96/01/17' + (Ilya's patched version.) + + `make --version` reports: 'GNU Make version 3.74' + (Ilya's patched version.) + + `emxrev` reports: + EMX : revision = 42 + EMXIO : revision = 40 + EMXLIBC : revision = 40 + EMXLIBCM : revision = 43 + EMXLIBCS : revision = 43 + EMXWRAP : revision = 40 + +----------------------------------------------------------------------------- + +Rocco +<troc@shadow.net> + diff --git a/os2/README.old b/os2/README.old deleted file mode 100644 index f49d6be1fa..0000000000 --- a/os2/README.old +++ /dev/null @@ -1,529 +0,0 @@ -This documentation to the previous version is somewhat applicable yet. -No system() extensions, no -R option, the exec/system with one argument -will use sh.exe only (if required). IZ - - Perl 5.001 for OS/2. - Patchlevel "m" - - Copyright (c) 1989,1990,1991,1992,1993,1994 Larry Wall - All rights reserved. - - OS/2 port Copyright (c) 1990, 1991, 1994-95 - Raymond Chen, Kai Uwe Rommel, Andreas Kaiser - -Version 5 port (this package) by Andreas Kaiser <ak@ananke.s.bawue.de> -(2:246/8506.9@fidonet). - -To run the executables supplied with this file, you have to install the -EMX runtime package emxrt.zip of version 0.9a05 (0.9a, fixlevel 5) or -later. - -The file emxrt.zip is available at ftp.rus.uni-stuttgart.de (the -origin), ftp-os2.nmsu.edu and many other places. - -The source code of the original Perl 5.0 distribution is not included -here. You can get it at ftp://ftp.wpi.edu:/perl5/perl5.001.tar.gz (and -many other places). - -For documentation of Perl 5, look at the files into the directory tree -"pod". For TeX or Postscript docs, get perlref-5.000.0.tar.gz. A LaTeX -and postscript reference card is available at - ftp.NL.net:/pub/comp/programming/languages/perl/perlref-5.000.0.tar.gz - prep.ai.mit.edu:/pub/gnu/perlref-5.000.0.tar.gz - -Many REXX DLLs complement the features available by standard Perl, -supporting system calls (YdbaUtil - RXU??.ZIP), xBase (RexxBase, -shareware), serial I/O (RxAsync) and basic PM dialogs (VRexx). These -packages can be found at many OS/2 FTP servers. - ------------------------------------------------------------------------------ -Installation: -------------- - -If you did not have HPFS up to now, this is the right time to reformat -your filesystem(s)... While Perl itself does not require HPFS, a lot -of Perl library files do. Or try EMXOPT=-t. - -copy perl5.exe perl5x.exe `some PATH dir` -copy os2\perlglob.exe `some PATH dir` -copy perl5.dll `some LIBPATH dir` - -set PERL5LIB=x:/your/own/perl/lib;y:/somewhere/perl5/lib - -The perl5 extension DLLs (POSIX_.DLL, REXX_.DLL, ...) do not need a -LIBPATH entry. - -Executables: ------------- - -perl5.exe,perl5.dll : DynaLoader, REXX support, external DLLs - - No fork. Running a command via open() returns 1 - instead of the child process id. - - Other modules supported via extension DLLs, no - builtins other than DynaLoader. - -perl5x.exe : No Dynaloader, no REXX. - - Supports fork. Running a command via open() uses fork - (slow) and correctly returns the child process id. - - POSIX and Socket modules builtin. No other extension - modules supported. - - Note that lib/Socket.pm and lib/POSIX.pm reflect - DLL use. If you need them with perl5x.exe, you - have to remove the "bootstrap" line. - ------------------------------------------------------------------------------ -Building: ---------- - -Requires: -- Perl5.001.tar.gz (Perl 5.001 sources). -- EMX 0.9a05 or later (Compiler). -- OS/2 Development Toolkit (or change REXX inc/lib references). -- Korn shell (ksh) or some other Unix-like shell named ksh. -- DMake, with group recipes configured for a Unix shell. -- Larry Walls "patch" program. -- Several Unix-like tools, such as cp, cat, touch, find, ... - -get Perl 5.001 source -apply patches\* -- "official unofficial" patches to 5.001 -apply os2\patches -- OS/2 platform patches -copy ext\DynaLoader\dl_os2.xs ext\DynaLoader\DynaLoader.xs -copy os2\config.sh . -copy os2\makefile.mk . - -If you do not have UPM (User Profile Management), remove "UPM" from -makefile.mk. - ------------------------------------------------------------------------------ -Not supported, bugs, "OS/2 is Not Unix": ----------------------------------------- - -Depending on whether you run perl5.exe or perl5x.exe, you can either -use extension modules and REXX, or fork, since the EMX implementation -of fork conflicts with DLL support. Remember that there is a hidden -fork in open(F, "-|") and open(F, "|-"). - -config.sh (Config.pm) lies. It shows d_fork='undef' even though it is -available in perl5x.exe. "dynamic_ext" and "extensions" are incorrect -for perl5x.exe. - -flock is available but does not yet work in EMX 0.9a. - -ttyname and ctermid do not work (return NULL). - -... and of course a lot of Unix-isms like process group, user and group -management, links, ... - -For details, look into config.sh and the EMX library reference. - -I did not test SDBM. I just added a lot of O_BINARY flags and compiled it. - -Several scripts of the test suite (see source distribution) fail due to -Unix-isms like /bin/sh, `echo *`, different quoting requirements, ... - -When opening a command pipe [such as open(F,"cat|")], perl5.exe -returns 1 instead of the child's process id. Perl5x.exe correctly -returns the process id. - -OS/2 does not have a true exec API (which is used both by the exec -function and when opening a command pipe with perl5x.exe). What -actually happens is the call of a subprocess with the father waiting -for the termination of its child. While waiting, the father still owns -all its resources (it passes signals to the child however) and there -may be some other side effects as well. - ------------------------------------------------------------------------------ -OS2::REXX Module (external library): ------------------------------------- - -NOTE: By default, the REXX variable pool is not available, neither to -Perl, nor to external REXX functions. To enable it, you have to start -Perl with the switch -R, which makes Perl call its interpreter through -REXX. REXX functions which do not use variables may be usable even -without -R though. - -Load REXX DLL: - - $dll = load OS2::REXX NAME [, WHERE]; - - NAME is DLL name, without path and extension. - - Directories are searched WHERE first (list of dirs), then - environment paths PERL5REXX, PERLREXX or, as last resort, PATH. - - The DLL is not unloaded when the variable dies. - - Returns DLL object reference, or undef on failure. - -Define function prefix: - - $dll->prefix(NAME); - - Define the prefix of external functions, prepended to the - function names used within your program, when looking for - the entries in the DLL. - - Example: - $dll = load OS2::REXX "RexxBase"; - $dll->prefix("RexxBase_"); - $dll->Init(); - is the same as - $dll = load OS2::REXX "RexxBase"; - $dll->RexxBase_Init(); - -Define queue: - - $dll->queue(NAME); - - Define the name of the REXX queue passed to all external - functions of this module. Defaults to "SESSION". - -Check for functions (optional): - - BOOL = $dll->find(NAME [, NAME [, ...]]); - - Returns true if all functions are available. - -Call external REXX function: - - $dll->function(arguments); - - Returns the return string if the return code is 0, else undef. - Dies with error message if the function is not available. - -Bind scalar variable to REXX variable: - - tie $var, OS2::REXX, "NAME"; - -Bind array variable to REXX stem variable: - - tie @var, OS2::REXX, "NAME."; - - Only scalar operations work so far. No array assignments, - no array operations, ... FORGET IT. - -Bind hash array variable to REXX stem variable: - - tie %var, OS2::REXX, "NAME."; - - To access all visible REXX variables via hash array, bind to ""; - - No array assignments. No array operations, other than hash array - operations. Just like the *dbm based implementations. - - For the usual REXX stem variables, append a "." to the name, - as shown above. If the hash key is part of the stem name, for - example if you bind to "", you cannot use lower case in the stem - part of the key and it is subject to character set restrictions. - -Erase individual REXX variables (bound or not): - - OS2::REXX::drop("NAME" [, "NAME" [, ...]]); - -Note that while function and variable names are case insensitive in the -REXX language, function names exported by a DLL and the REXX variables -(as seen by Perl through the chosen API) are all case sensitive! - -Most REXX DLLs export function names all upper case, but there are a -few which export mixed case names (such as RxExtras). When trying to -find the entry point, both exact case and all upper case are searched. -If the DLL exports "RxNap", you have to specify the exact case, if it -exports "RXOPEN", you can use any case. - -To avoid interfering with subroutine names defined by Perl (DESTROY) -or used within the REXX module (prefix, find), it is best to use mixed -case and to avoid lowercase only or uppercase only names when calling -REXX functions. Be consistent. The same function written in different -ways results in different Perl stubs. - -There is no REXX interpolation on variable names, so the REXX variable -name TEST.ONE is not affected by some other REXX variable ONE. And it -is not the same variable as TEXT.one! - -You cannot call REXX functions which are not exported by the DLL. -While most DLLs export all their functions, some, like RxFTP, export -only "...LoadFuncs", which registers the functions within REXX only. - -You cannot call 16-bit DLLs. The few interesting ones I found -(FTP,NETB,APPC) do not export their functions. - -I do not know whether the REXX API is reentrant with respect to -exceptions (signals) when the REXX top-level exception handler is -overridden. So unless you know better than I do, do not access REXX -variables (probably tied to Perl variables) or call REXX functions -which access REXX queues or REXX variables in signal handlers. - -See ext/OS2/REXX/rx*.pl for examples. - ------------------------------------------------------------------------------ -OS2::UPM (external library): ----------------------------- - -UPM constants (see <upm.h>) are exported automatically, functions only -on request. - -(USERID, TYPE) = local_user () - - return local user - -LIST = user_list (REMOTENODE="", REMOTETYPE_UPM_LOCAL) - LIST = 4 items per logged on user - [0] = user id - [1] = remote node name - [2] = remote node type (INT) - [3] = session id (INT) - -(USERID, TYPE) = local_logon () - - do a local logon, PM window, if not already logged on - -BOOL = logon (USERID, PASSWORD, AUTHCHECK=UPM_USER, REMOTENODE="", REMOTETYPE=UPM_LOCAL) -BOOL = logoff (USERID, REMOTENODE="", REMOTETYPE=UPM_LOCAL) - - logon/logoff process (DB2/2) - -BOOL = logon_user (USERID, PASSWORD, REMOTENODE="", REMOTETYPE=UPM_LOCAL) -BOOL = logoff_user (USERID, REMOTENODE="", REMOTETYPE=UPM_LOCAL) - - logon/logoff user - -ERRCODE = error () - - return UPM error code of last failure - -STRING = message (ERRCODE) - - return message text for supplied UPM error code - -Defaults: - REMOTETYPE = UPM_LOCAL - REMOTENODE = "" - AUTHCHECK = UPM_USER - ------------------------------------------------------------------------------ -OS2::FTP (external library): ----------------------------- - -$acct = new FTP "host", "userid", "passwd" [, "acct"] - - Create virtual FTP session - no login. - -FTP::logoff() - - Logoff all sessions. - -($msec, $address) = FTP::ping("host", pktlen); -$msec = FTP::ping($address, pktlen); - - Ping host. Returns milliseconds or negative error code. - $address is 32-bit number. - -$errno = $acct->errno(); - - Return last error code (FTP*). - -$text = FTP::message($errno); - - Return message test of last error. - -$status: <0 on error, >=0 on success. -$tfrtype: T_BINARY, T_ASCII, T_EBCDIC -"mode": "w" for overwrite, "a" for append - -$status = $acct->dir("local", "pattern"="*"); -$status = $acct->ls("local", "pattern"="*"); - -$status = $acct->chdir("dir"); -$status = $acct->mkdir("dir"); -$status = $acct->rmdir("dir"); -($status, $cwd) = $acct->getcwd(); - -$status = $acct->get("local", "remote"=local, "mode"="w", $tfrtype=T_BINARY); - -$status = $acct->put("local", "remote"=local, $tfrtype=T_BINARY); -$status = $acct->putunique("local", "remote"=local, $tfrtype=T_BINARY); -$status = $acct->append("local", "remote"=local, $tfrtype=T_BINARY); - -$status = $acct->rename("from", "to"); -$status = $acct->delete("name"); - -$status = $acct->proxy($source_acct, "dst_file", "src_file", $tfrtype=T_BINARY); - -$status = $acct->quote("string"); -$status = $acct->site("string"); -($status, $infostring) = $acct->sys(); - ------------------------------------------------------------------------------ -Other: ------- - - setpriority CLASS,PID,DELTA - - Set priority of process or process tree. - - PID: - >= 0: process only - < 0: process tree - - CLASS: - 0 no change - 1 idle-time (lowest) - 2 regular (dynamic priority) - 3 time-critical (highest) - 4 fixed-high (between regular and time-critical) - - DELTA: - -31..+31 - - getpriority IGNORED,PID - - Return priority of process or process tree. - - Bits 8..15 priority class (1..4) - Bits 0..7 priority within class (0..31) - - system LIST - - If the first element of LIST is an integer, it controls the - started child process or session as follows: - - 0 = wait until child terminates (default) - 1 = do not wait, use wait() or waitpid() for status - 4 = new session - 5 = detached - 6 = PM program - - PM and session options, or-ed in: - - 0x00000 = default - 0x00100 = minimized - 0x00200 = maximized - 0x00300 = fullscreen (session only) - 0x00400 = windowed (session only) - - 0x00000 = foreground (only if running in foreground) - 0x01000 = background - - 0x02000 = don't close window on exit (session only) - - 0x10000 = quote all arguments - 0x20000 = MKS argument passing convention - - If the control is not zero, system() does not wait until - the child terminates and the return code is the id of the - child process. - - If the control is not zero, and you do not call wait or - waitpid, the child status fills up memory. - - Note: If the program is started with a mode of 4 or 6, it may - be aborted when the starting program (perl) terminates. Later - releases of EMX.DLL will probably know yet another flag bit - to cut this fatal relationship. - - system STRING - exec STRING - - If the string starts with "@" or contains any of "%&|<>", - it is called as a shell command. Else the program is called - directly. - - If the environment variable SHELL is defined, it is used - instead of COMSPEC when running shell commands. It should - be a Unix-style shell. - - file checks (-X), stat(), ... - - When testing filenames, not handles, char-devices are detected - only when prefixed by "/dev/", so "/dev/con" is valid, "con" is - not. - - Currently, only /dev/con and /dev/tty are recognized. - ------------------------------------------------------------------------------ -History: - -15.12.94 Initial release (perl5000.zip). - -17.12.94 Moved REXX sub defn to find(). Hash array for functions no - longer required, allows overriding subs like "find". - - DLL entries are case sensitive, try both upper case and - exact case. - -18.12.94 Detect char- and block-devices (stat() hack). Some future - release may probably remove block device support, once - char-device support is built into EMX. - - Fixed perl5db tty check. - -22.12.94 EMX fixlevel 2 exports its exception handler, so now - signals work even when the REXX variable pool is enabled. - - Disabled error and exception popups. - -27.12.94 Case conversions of tied variables cleaned up. - - REXX (REXX.DLL, REXXAPI.DLL) now loaded on demand. - -7.1.95 Fixed Shell module (did not allow more than one argument). - -11.1.95 Accept drive letter as absolute path in do/require/use. - -13.1.95 Larrys memory-leak patches (#1, dated Friday 13). - -26.1.95 fcntl and ioctl were missing. fcntl was explicitly disabled - in its source code (ifndef DOSISH) and the ioctl enabler is - in the wrong place (unixish.h instead of config.sh). - -16.3.95 DosQueryFSAttach (stat hack) may crash the system. Now just - look for /dev/con and /dev/tty. - - Applied "pad_findlex" patch (patches/1). - -23.3.95 Support fork. Two executables, one for DLLs and one for fork. - -24.3.95 5.001 - -13.4.95 Patchlevel "c". - -21.4.95 Truncate names of extension DLLs to 8 chars - Warp no longer - accepts them (2.x did). - -22.4.95 Replaced EMX dirent by my own to get all directory entries - even when HPFS386 is used. Additionally, my implementation - is not restricted in the total size of the directory (a - conflict between Perls memory allocator and the one of the - EMX library DLL). - -27.4.95 Support for fork() disabled system() in DLL version. - -7.5.95 Added Tye McQueen's FileGlob. See File::KGlob*. - -12.5.95 Fixed Cwd. Fixed OS/2 dependencies in MakeMaker, with - a few Config.sh items added (separators, exe-extension). - - Moved UPM and REXX to OS2::. Combined REXXCALL and REXX. - Plain old REXX module is still available as passthru though. - - Perl DLLs now have an underscore appended to avoid name - conflicts with standard OS/2 DLLs (see DynaLoader.pm). - -13.5.95 Added FTP API support (OS2::FTP). - -2.7.95 Applied "official unofficial" patches up to level "m". - The modpods documentation now is in the modules themselves. - -4.7.95 Implement command pipes (my_popen) using fork instead of - standard popen in the fork version (perl5x.exe). While this - is a lot slower, it correctly returns the process id and - supports open(F,"-|") and open(F,"|-"). - - Use the same code for exec(CMD) as for system(CMD). - - Support socket functions (set|get|end)(host|net|proto|serv)ent. diff --git a/os2/diff.configure b/os2/diff.configure index 53aa16b4a2..f687898f0c 100644 --- a/os2/diff.configure +++ b/os2/diff.configure @@ -288,19 +288,21 @@ cryptlib=-lcrypt fi *************** -*** 5198,5204 **** - } +*** 5198,5205 **** EOM + : Call the object file tmp-dyna.o in case dlext=o. if $cc $ccflags $cccdlflags -c dyna.c > /dev/null 2>&1 && -! $ld $lddlflags -o dyna.$dlext dyna.o > /dev/null 2>&1 && +! mv dyna.o tmp-dyna.o > /dev/null 2>&1 && +! $ld $lddlflags -o dyna.$dlext tmp-dyna.o > /dev/null 2>&1 && $cc $ccflags $ldflags $cccdlflags $ccdlflags fred.c -o fred $libs > /dev/null 2>&1; then xxx=`./fred` case $xxx in ---- 5213,5219 ---- - } +--- 5213,5220 ---- EOM + : Call the object file tmp-dyna.o in case dlext=o. if $cc $ccflags $cccdlflags -c dyna.c > /dev/null 2>&1 && -! $ld $lddlflags -o dyna.$dlext dyna$obj_ext > /dev/null 2>&1 && +! mv dyna$obj_ext tmp-dyna$obj_ext > /dev/null 2>&1 && +! $ld $lddlflags -o dyna.$dlext tmp-dyna$obj_ext > /dev/null 2>&1 && $cc $ccflags $ldflags $cccdlflags $ccdlflags fred.c -o fred $libs > /dev/null 2>&1; then xxx=`./fred` case $xxx in diff --git a/os2/dlfcn.h b/os2/dlfcn.h index df2ea33d32..c96f97f82d 100644 --- a/os2/dlfcn.h +++ b/os2/dlfcn.h @@ -1,6 +1,3 @@ void *dlopen(char *path, int mode); void *dlsym(void *handle, char *symbol); char *dlerror(void); -void *dlopen(char *path, int mode); -void *dlsym(void *handle, char *symbol); -char *dlerror(void); @@ -1,10 +1,8 @@ #define INCL_DOS #define INCL_NOPM #define INCL_DOSFILEMGR -#ifndef NO_SYS_ALLOC -# define INCL_DOSMEMMGR -# define INCL_DOSERRORS -#endif /* ! defined NO_SYS_ALLOC */ +#define INCL_DOSMEMMGR +#define INCL_DOSERRORS #include <os2.h> /* @@ -137,10 +135,15 @@ result(int flag, int pid) int r, status; Signal_t (*ihand)(); /* place to save signal during system() */ Signal_t (*qhand)(); /* place to save signal during system() */ +#ifndef __EMX__ + RESULTCODES res; + int rpid; +#endif - if (pid < 0 || flag != 0) + if (pid < 0 || flag != 0) return pid; +#ifdef __EMX__ ihand = signal(SIGINT, SIG_IGN); qhand = signal(SIGQUIT, SIG_IGN); do { @@ -153,6 +156,15 @@ result(int flag, int pid) if (r < 0) return -1; return status & 0xFFFF; +#else + ihand = signal(SIGINT, SIG_IGN); + r = DosWaitChild(DCWA_PROCESS, DCWW_WAIT, &res, &rpid, pid); + signal(SIGINT, ihand); + statusvalue = res.codeResult << 8 | res.codeTerminate; + if (r) + return -1; + return statusvalue; +#endif } int @@ -170,7 +182,7 @@ register SV **sp; New(401,Argv, sp - mark + 1, char*); a = Argv; - if (mark < sp && SvIOKp(*(mark+1))) { + if (mark < sp && SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) { ++mark; flag = SvIVx(*mark); } @@ -187,8 +199,12 @@ register SV **sp; if (flag == P_WAIT) flag = P_NOWAIT; - if (*Argv[0] != '/' && *Argv[0] != '\\') /* will swawnvp use PATH? */ + if (*Argv[0] != '/' && *Argv[0] != '\\' + && !(*Argv[0] && *Argv[1] == ':' + && (*Argv[2] == '/' || *Argv[2] != '\\')) + ) /* will swawnvp use PATH? */ TAINT_ENV(); /* testing IFS here is overkill, probably */ + /* We should check PERL_SH* and PERLLIB_* as well? */ if (really && *(tmps = SvPV(really, na))) rc = result(trueflag, spawnvp(flag,tmps,Argv)); else @@ -203,9 +219,14 @@ register SV **sp; return rc; } +#define EXECF_SPAWN 0 +#define EXECF_EXEC 1 +#define EXECF_TRUEEXEC 2 + int -do_spawn(cmd) +do_spawn2(cmd, execf) char *cmd; +int execf; { register char **a; register char *s; @@ -254,10 +275,17 @@ char *cmd; break; } doshell: + if (execf == EXECF_TRUEEXEC) + return execl(shell,shell,copt,cmd,(char*)0); + else if (execf == EXECF_EXEC) + return spawnl(P_OVERLAY,shell,shell,copt,cmd,(char*)0); + /* In the ak code internal P_NOWAIT is P_WAIT ??? */ rc = result(P_WAIT, - spawnl(P_NOWAIT,shell,shell,copt,cmd,(char*)0)); + spawnl(P_NOWAIT,shell,shell,copt,cmd,(char*)0)); if (rc < 0 && dowarn) - warn("Can't spawn \"%s\": %s", shell, Strerror(errno)); + warn("Can't %s \"%s\": %s", + (execf == EXECF_SPAWN ? "spawn" : "exec"), + shell, Strerror(errno)); if (rc < 0) rc = 255 << 8; /* Emulate the fork(). */ return rc; } @@ -276,9 +304,16 @@ char *cmd; } *a = Nullch; if (Argv[0]) { - rc = result(P_WAIT, spawnvp(P_NOWAIT,Argv[0],Argv)); + if (execf == EXECF_TRUEEXEC) + rc = execvp(Argv[0],Argv); + else if (execf == EXECF_EXEC) + rc = spawnvp(P_OVERLAY,Argv[0],Argv); + else + rc = result(P_WAIT, spawnvp(P_NOWAIT,Argv[0],Argv)); if (rc < 0 && dowarn) - warn("Can't spawn \"%s\": %s", Argv[0], Strerror(errno)); + warn("Can't %s \"%s\": %s", + (execf == EXECF_SPAWN ? "spawn" : "exec"), + Argv[0], Strerror(errno)); if (rc < 0) rc = 255 << 8; /* Emulate the fork(). */ } else rc = -1; @@ -286,12 +321,36 @@ char *cmd; return rc; } +int +do_spawn(cmd) +char *cmd; +{ + return do_spawn2(cmd, EXECF_SPAWN); +} + +bool +do_exec(cmd) +char *cmd; +{ + return do_spawn2(cmd, EXECF_EXEC); +} + +bool +os2exec(cmd) +char *cmd; +{ + return do_spawn2(cmd, EXECF_TRUEEXEC); +} + #ifndef HAS_FORK FILE * my_popen(cmd,mode) char *cmd; char *mode; { +#ifdef TRYSHELL + return popen(cmd, mode); +#else char *shell = getenv("EMXSHELL"); FILE *res; @@ -299,6 +358,7 @@ char *mode; res = popen(cmd, mode); my_setenv("EMXSHELL", shell); return res; +#endif } #endif @@ -323,18 +383,54 @@ void * ctermid(x) { return 0; } void * ttyname(x) { return 0; } #endif -void * gethostent() { return 0; } -void * getnetent() { return 0; } -void * getprotoent() { return 0; } -void * getservent() { return 0; } -void sethostent(x) {} -void setnetent(x) {} -void setprotoent(x) {} -void setservent(x) {} -void endhostent(x) {} -void endnetent(x) {} -void endprotoent(x) {} -void endservent(x) {} +/*****************************************************************************/ +/* my socket forwarders - EMX lib only provides static forwarders */ + +static HMODULE htcp = 0; + +static void * +tcp0(char *name) +{ + static BYTE buf[20]; + PFN fcn; + if (!htcp) + DosLoadModule(buf, sizeof buf, "tcp32dll", &htcp); + 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 (!htcp) + DosLoadModule(buf, sizeof buf, "tcp32dll", &htcp); + if (htcp && DosQueryProcAddr(htcp, 0, name, &fcn) == 0) + ((void (*)(int)) fcn) (arg); +} + +void * gethostent() { return tcp0("GETHOSTENT"); } +void * getnetent() { return tcp0("GETNETENT"); } +void * getprotoent() { return tcp0("GETPROTOENT"); } +void * 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++ */ + +#ifndef __EMX__ +int setuid(x) { errno = EINVAL; return -1; } +int setgid(x) { errno = EINVAL; return -1; } +#endif /*****************************************************************************/ /* stat() hack for char/block device */ @@ -362,55 +458,22 @@ os2_stat(char *name, struct stat *st) #endif -#ifndef NO_SYS_ALLOC - -static char *oldchunk; -static long oldsize; +#ifdef USE_PERL_SBRK -#define _32_K (1<<15) -#define _64_K (1<<16) - -/* The real problem is that DosAllocMem will grant memory on 64K-chunks - * boundaries only. Note that addressable space for application memory - * is around 240M, thus we will run out of addressable space if we - * allocate around 14M worth of 4K segments. - * Thus we allocate memory in 64K chunks, and abandon the rest of the old - * chunk if the new is bigger than that rest. Also, we just allocate - * whatever is requested if the size is bigger that 32K. With this strategy - * we cannot lose more than 1/2 of addressable space. */ +/* SBRK() emulation, mostly moved to malloc.c. */ void * -sbrk(int size) -{ - char *got; - APIRET rc; - int small, reqsize; - - if (!size) return 0; - else if (size <= oldsize) { - got = oldchunk; - oldchunk += size; - oldsize -= size; - return (void *)got; - } else if (size >= _32_K) { - small = 0; - } else { - reqsize = size; - size = _64_K; - small = 1; - } - rc = DosAllocMem((void **)&got, size, PAG_COMMIT | PAG_WRITE); +sys_alloc(int size) { + void *got; + APIRET rc = DosAllocMem(&got, size, PAG_COMMIT | PAG_WRITE); + if (rc == ERROR_NOT_ENOUGH_MEMORY) { return (void *) -1; } else if ( rc ) die("Got an error from DosAllocMem: %li", (long)rc); - if (small) { - /* Chunk is small, register the rest for future allocs. */ - oldchunk = got + reqsize; - oldsize = size - reqsize; - } - return (void *)got; + return got; } -#endif /* ! defined NO_SYS_ALLOC */ + +#endif /* USE_PERL_SBRK */ /* tmp path */ @@ -463,8 +526,8 @@ mod2fname(sv) SV *sv; { static char fname[9]; - int pos = 7; - int len; + int pos = 6, len, avlen; + unsigned int sum = 0; AV *av; SV *svp; char *s; @@ -473,13 +536,30 @@ mod2fname(sv) sv = SvRV(sv); if (SvTYPE(sv) != SVt_PVAV) croak("Not array reference given to mod2fname"); - if (av_len((AV*)sv) < 0) + + avlen = av_len((AV*)sv); + if (avlen < 0) croak("Empty array reference given to mod2fname"); - s = SvPV(*av_fetch((AV*)sv, av_len((AV*)sv), FALSE), na); + + s = SvPV(*av_fetch((AV*)sv, avlen, FALSE), na); strncpy(fname, s, 8); - if ((len=strlen(s)) < 7) pos = len; - fname[pos] = '_'; - fname[pos + 1] = '\0'; + len = strlen(s); + if (len < 6) pos = len; + while (*s) { + sum = 33 * sum + *(s++); /* Checksumming first chars to + * get the capitalization into c.s. */ + } + avlen --; + while (avlen >= 0) { + s = SvPV(*av_fetch((AV*)sv, avlen, FALSE), na); + while (*s) { + sum = 33 * sum + *(s++); /* 7 is primitive mod 13. */ + } + avlen --; + } + fname[pos] = 'A' + (sum % 26); + fname[pos + 1] = 'A' + (sum / 26 % 26); + fname[pos + 2] = '\0'; return (char *)fname; } @@ -525,9 +605,9 @@ Xs_OS2_init() newXS("File::Copy::syscopy", XS_File__Copy_syscopy, file); newXS("DynaLoader::mod2fname", XS_DynaLoader_mod2fname, file); -#ifdef PERL_IS_AOUT gv = gv_fetchpv("OS2::is_aout", TRUE, SVt_PV); GvMULTI_on(gv); +#ifdef PERL_IS_AOUT sv_setiv(GvSV(gv), 1); #endif } @@ -542,10 +622,62 @@ Perl_OS2_init() OS2_Perl_data.xs_init = &Xs_OS2_init; if ( (shell = getenv("PERL_SH_DRIVE")) ) { sh_path[0] = shell[0]; + } else if ( (shell = getenv("PERL_SH_DIR")) ) { + int l = strlen(shell); + if (shell[l-1] == '/' || shell[l-1] == '\\') { + l--; + } + if (l > STATIC_FILE_LENGTH - 7) { + die("PERL_SH_DIR too long"); + } + strncpy(sh_path, shell, l); + strcpy(sh_path + l, "/sh.exe"); } } -char sh_path[33] = BIN_SH; +char sh_path[STATIC_FILE_LENGTH+1] = BIN_SH; + +char * +perllib_mangle(char *s, unsigned int l) +{ + static char *newp, *oldp; + static int newl, oldl, notfound; + static char ret[STATIC_FILE_LENGTH+1]; + + if (!newp && !notfound) { + newp = getenv("PERLLIB_PREFIX"); + if (newp) { + oldp = newp; + while (*newp && !isSPACE(*newp)) { + newp++; oldl++; /* Skip digits. */ + } + while (*newp && (isSPACE(*newp) || *newp == ';')) { + newp++; /* Skip whitespace. */ + } + newl = strlen(newp); + if (newl == 0 || oldl == 0) { + die("Malformed PERLLIB_PREFIX"); + } + } else { + notfound = 1; + } + } + if (!newp) { + return s; + } + if (l == 0) { + l = strlen(s); + } + if (l <= oldl || strnicmp(oldp, s, oldl) != 0) { + return s; + } + if (l + newl - oldl > STATIC_FILE_LENGTH || newl > STATIC_FILE_LENGTH) { + die("Malformed PERLLIB_PREFIX"); + } + strncpy(ret, newp, newl); + strncpy(ret + newl, s + oldl, l - oldl); + return ret; +} extern void dlopen(); void *fakedl = &dlopen; /* Pull in dynaloading part. */ diff --git a/os2/os2ish.h b/os2/os2ish.h index 917f515112..12c6ad337e 100644 --- a/os2/os2ish.h +++ b/os2/os2ish.h @@ -45,7 +45,7 @@ #endif #define ABORT() kill(getpid(),SIGABRT); -#define BIT_BUCKET "/dev/null" /* Will this work? */ +#define BIT_BUCKET "/dev/nul" /* Will this work? */ void Perl_OS2_init(); @@ -62,8 +62,18 @@ void Perl_OS2_init(); #define dXSUB_SYS int fake = OS2_XS_init() #ifdef PERL_IS_AOUT -#define NO_SYS_ALLOC -#endif +# define HAS_FORK +/* # define HIDEMYMALLOC */ +/* # define PERL_SBRK_VIA_MALLOC */ /* gets off-page sbrk... */ +#else /* !PERL_IS_AOUT */ +# ifndef PERL_FOR_X2P +# define USE_PERL_SBRK +# endif +# define SYSTEM_ALLOC(a) sys_alloc(a) + +void *sys_alloc(int size); + +#endif /* !PERL_IS_AOUT */ #define TMPPATH tmppath #define TMPPATH1 "plXXXXXX" @@ -160,8 +170,11 @@ extern OS2_Perl_data_t OS2_Perl_data; set_Perl_HAB_f; \ } -extern char sh_path[33]; +#define STATIC_FILE_LENGTH 127 +extern char sh_path[STATIC_FILE_LENGTH+1]; #define SH_PATH sh_path +#define PERLLIB_MANGLE(s, n) perllib_mangle((s), (n)) +char *perllib_mangle(char *, unsigned int); char *os2error(int rc); diff --git a/os2/perl2cmd.pl b/os2/perl2cmd.pl index aa1c353f13..c17ab761aa 100644 --- a/os2/perl2cmd.pl +++ b/os2/perl2cmd.pl @@ -16,7 +16,8 @@ EOU $idir = $Config{installbin}; $indir =~ s|\\|/|g ; -foreach $file (<$idir/*.>) { +foreach $file (<$idir/*>) { + next if $file =~ /\.exe/i; $base = $file; $base =~ s/\.$//; # just in case... $base =~ s|.*/||; |