pax_global_header 0000666 0000000 0000000 00000000064 12071203757 0014516 g ustar 00root root 0000000 0000000 52 comment=7c4a910bab48160cca35117a59e3e58aa8d2233d
psad-7c4a910/ 0000775 0000000 0000000 00000000000 12071203757 0012777 5 ustar 00root root 0000000 0000000 psad-7c4a910/BENCHMARK 0000664 0000000 0000000 00000006753 12071203757 0014227 0 ustar 00root root 0000000 0000000 Kmsgsd Benchmarks:
The basic strategy in benchmarking kmsgsd is to get syslogd to write kern.info
messages (which include iptables log messages) to the
/var/lib/psad/psadfifo named pipe. Kmsgsd will then read the messages out of the
pipe as quickly as possible and write them to /var/log/psad/fwdata. To
calculate how fast kmsgsd is we then compare the number of newly written
firewall messages to /var/log/messages with the number of messages kmsgsd was
able to write to /var/log/psad/fwdata in the same time frame. To generate lots
of firewall "deny" messages we first make sure we have the firewall "default
log and deny" policy loaded, and then proceed to scan the firewall first from a
machine that is linked via a 100MB ethernet segment connected directly to the
firewall with a crossover cable, and second with a scan against the loopback
address from the firewall itself. The second scan will eliminate any network
latency from slowing the scan down.
TEST 1:
- Scanning machine: PIII 700mhz, kernel 2.2.18
- Target machine: PIII 700mhz, kernel 2.4.0
- Ethernet: 100MB connection between the two machines.
- Perl: 5.005_03
- Scan command line: nmap -sX -p 5000-60000
- Approximate average number of iptables "DROP" messages printed to
/var/log/messages: 4400
- Approximate average number of iptables messages caught by kmsgsd and
printed to /var/log/psad/fwdata: 4325
Results: kmsgsd catches over 98% of all firewall messages that are
written by klogd to /var/log/messages. The remaining two percent that
are missed is probably due to context switching overhead and/or slowness
of Perl itself, and not much can be done about that (except re-writing it
in C of course).
TEST 2:
- We scan the loopback interface on the firewall.
- PIII 500mhz, 128 MB ram, kernel 2.4.0
- Perl 5.005_03
- Scan command line: nmap -sX -p 5000-60000 127.0.0.1
- Number of iptables "DROP" messages printed to /var/log/messages: 14810
- Number of iptables messages caught by kmsgsd and written to
/var/log/psad/fwdata: 14847
Results: These results are a bit surprising since kmsgsd caught more
messages in /var/log/psad/fwdata than syslog could write to
/var/log/messages, but perhaps syslog can write more quickly to a named pipe
(in this case to /var/lib/psad/psadfifo) than it can to a file (/var/log/messages)
since probably would not have seek() to the end of the file to know where to
write each message. Hence it would appear that kmsgsd can keep up with just
about anything thrown at it (for home users anyway). During this test kmsgsd
had a maximum CPU utilization of 5.6% and a maximum memory utilization of
0.8%
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Psad Benchmarks:
To benchmark psad we need to generate lots of messages in the fwdata file.
Normally this is the responsibility of kmsgsd, but to perform an effective test
of just how fast psad is able to parse lots of firewall "deny" messages, we
first create a large file that contains 10,000 lines of the firewall messages,
then we execute "cat /dev/null > /var/log/psad/fwdata", and lastly we copy the
large file to /var/log/psad/fwdata. Psad then detects that 10,000 packets were
just logged by the firewall and starts to process the lines one by one.
- PIII 500mhz, 128MB ram, kernel 2.4.0
- Perl 5.005_03
Results: Psad was able to process all 10,000 lines of firewall messages in
approximately 16 seconds with a peak CPU and memory utilization of 99.7% and
3.8% respectively.
psad-7c4a910/CREDITS 0000664 0000000 0000000 00000046414 12071203757 0014030 0 ustar 00root root 0000000 0000000 Albert E. Whale
- Discovered bug in 1.1 that made fw_check() too strict with looking for
precisely FW_MSG_SEARCH in a logging prefix instead of just looking
for FW_MSG_SEARCH _within_ the logging prefix.
- Suggested use of CPAN downloads of perl modules in install.pl.
- Bugfix for "-" character missing from Mandrake version of ps.
- Bugfix for duplicate lines for tcpwrapper auto block IPs in
/etc/hosts.deny.
- Lots of great testing and feedback on new versions and -pre releases.
- Suggested the ability to re-import scanning IP directories.
- Bugfix for zero print_scale_factor in --Analyze-msgs mode.
- Bugfix for auto-ignored addresses appearing in DShield alerts.
- Bugfix for not timing-out blocked IP addresses from a previous psad
execution.
- Suggested putting -pre release versions in psad to make
troubleshooting easier.
- Discovered bug in syslog() message generation and --fw-block arg.
- Lots of great testing for auto-blocking code... even contributed
root access on some systems to help troubleshoot.
- Suggested socket communication in --fw-block mode.
- Contributed the logrotate.psad file.
- Suggested that the AUTO_IPT_SOCK file get recreated if some other
process comes in and deletes it.
- Suggested psadwatchd parse EMAIL_ADDRESSES from psad.conf.
- Found bug where auto-blocking stops working after receiving a HUP
signal.
- Found bug for not properly including elements of the
@connected_subnets_cidr array.
- Found bug for not using thresholds in "top attackers" section of
--Status output.
- Helped troubleshoot the PL_sv_undef issue for installation on Mandriva
systems.
- Discovered IP resolution bug in psad-2.1 for auto_dl lines.
Manual Caphina
- Greatly assisting in the first version of Bastille-NIDS which
eventually became psad.
Tim Schaller
- Identifying and submitting a patch for a particularly nasty bug for
multiple scanned IPs.
Bruce Meyer
- Psad testing and suggestions.
Peter Watkins
- (Bastille Linux) psad/iptables interaction.
Sweth Chandramouli
- (Bastille Linux) Various suggestions for psad and install.pl,
including help with various Perl vagaries.
Jay Beale
- (Bastille Linux) Excellent suggestions for psad reporting and enhanced
security, and also for integrating psad with Bastille.
Ramiro Morales
- Developed all pre-1.0 rpm packages of psad (see:
http://rmrpms.tripod.com/psad/).
- Various suggestions for psad installation (such as FHS compatibility).
- Implemented init script patches.
Alexander Hoff
- Psad stress testing for kmsgsd.
Ryan Delany
- diskmond testing to help track down the "rdev" bug.
Damien Stuart
- Suggested the zombie reaper code for whois processes, and uid/gid
check.
- Excellent suggestions for coding practices and strategies.
Donnie Armstrong
- Suggested fix for incorrectly parsing ifconfig output (might have
previously included ipv6 interfaces).
Ryan Bebeau
- Suggested fix for AF_INET protocol error.
Cliff Rayman
- Helped track down a nasty bug in which psad would parse iptables
messages that included a dns name instead of just an ip address for
the src and dst.
- Performed lots of excellent testing and
troubleshooting.
Henry Jobst
- Bugfix in install.pl for chomp error.
Ray Curtis
- Found bug in kmsgsd for undefined $service lines.
- Comprehensive testing to help remove bugs including a difficult one in
which psad gets periodically restarted.
Manuel Santos
- Contributed the first bug report to help troublehshoot a potential bug
in psad/whois interaction.
- Suggested the auto blocking code should include support for tcp
wrappers, and that the auto-blocking alerts should be configurable.
L-P Sundqvist
- Suggested fix for tab vs. space bug in install.pl for
/etc/syslog.conf.
- Contributed design ideas to make psad run on linux distros that use
BSD-style init scripts.
Eric Sawler
- Suggested the ability to retain auto-blocked IPs even after a reboot.
C.Holman
- Found, reported, and helped troubleshoot a bug in the ipchains
protocol number to name mapping.
Mike McCandless
- Asked whether or not there is documentation for the various psad
configuration variables in psad.conf. The "PSAD CONFIGURATION
VARIABLES" section of the man page was the result.
Jason Czerak
- Found and submitted a fix for a bug in which an IP would not be
ignored even if it was given a 0 danger level in psad_auto_ips.
- Suggested using the PREROUTING iptables chain along with "-t mangle"
for the auto-blocking code.
Colin Rose
- Discovered and helped troubleshoot a bug introduced when psad and
bastille are installed on the same machine (bastille installs an older
version of psad).
Ugo Viti
- Discovered bug in auto-blocking code where the subject line would
incorrectly identify the action that had been taken.
- Discovered bug in subject line for alert emails not including the
source IP if reverse dns did not work.
- Suggested adding the FORWARD chain to the auto blocking code.
- Found bug for email alert being reached prematurely.
Leif Westlye
- Discovered a bug where psad would not allow commands to be different
than the Cmd name. The bugfix allows someone to specify
"/usr/bin/mailto" for the mailCmd for example.
Daniel Gubser
- Wrote the diskmond, kmsgsd, and psadwatchd man pages.
- Suggested compatibility mods for syslog-ng.
- Develops and maintains Debian builds.
Amelia Lewis
- Provided information on syslog-ng configs.
Nick Temple
- Suggested sending alerts to abuse.net.
James N. Winner
- Discovered bug that prevented psad from detecting scans through the
iptables FORWARD chain.
David Krider
- Discovered iptables path bug on SuSE 8.2.
Ciapato Manfredi
- Reported psadwatchd bug where multiple useless processes were being
spawned.
Ben Alcala
- Helped troubleshoot diskmond utilization bug.
Sebastian Mastropiero
- Suggested bugfix for missing pipe character in psad man page for
psadfifo line in syslog.conf.
Jeff Lunglhofer
- Suggested bugfix for packet counters and multiple scan destinations,
bugfix for duplicate lines in auto-blocking files, and suggested
feature by which psad can add auto blocking firewall rules at
arbitrary points within a policy.
Ruben Vanhoutte
- Bugfix for incorrect path to psadfifo in syslog.ng config.
Stefan Divjak
- Suggested that psad ignore addresses such as 0.0.0.0, 127.0.0.1, and
local interface ips from auto blocking routines.
- Suggested a generic way to (un)block addresses using an external
script.
- Suggested psad offer analysis capabilities for snort alert files.
Martijn Kruissen
- Suggested putting danger levels into psad email alert subjects.
- Suggested custom logging line that that will trigger psad to auto
block an IP.
Jeffrey Sofferin
- Lots of great testing for conditions that might cause psad to die.
- Bugfix in man page for -HUP option.
- Suggested the --status-dl option.
- Suggested MIN_ARCHIVE_DANGER_LEVEL.
- Found bug for 24 hour dshield alerting interval.
- Found bug for not preserving user modifications in auto_dl file.
- Found bug on SuSE systems running syslog-ng where the syslog-ng.conf
reconfig added by psad caused the daemon to not start.
- Found initialization bug that caused signature danger levels to not
be properly assigned by the /etc/psad/snort_rule_dl file.
Kenneth Grande
- Suggested protocol-specific thresholds for email alerts.
Lenny Cartier
- Wrote a spec file for Mandrake Linux. An rpm built from this spec
file is in the user contribs section of the Mandrake site now.
Bryan Stine
- Wrote a psad ebuild script for inclusion in Gentoo Linux. As of the
1.2.4 release psad is included in the portage tree.
- Wrote a much-improved init script for Gentoo systems.
Zenon Panoussis
- Submitted patch for rpm spec that replaced the "Requires: sendmail"
line with "Requires: smtpdaemon".
Dennis Freise
- Submitted a patch to add metalog support to psad.
- Helped find kmsgsd bug for missing null string in buffer read from
psadfifo.
- Submitted patch for kmsgsd to open psadfifo in O_RDWR mode to fix a
bug where kmsgsd would spike the cpu if the system logger did not keep
the psadfifo open.
- Found and submitted patch for improper bounds checking in kmsgsd.c.
Richard K. Szabo
- Discovered and helped test a bug where psad was not honoring IP's/net
auto danger level assignments of 0 (ignore).
Stefan Rydberg
- Discovered a perl internal pp_match bug with psad-1.3.1 on SuSE 8.
- Helped troubleshoot -pre releases of psad-1.3.2.
- Provided a system on which to troubleshoot psad-1.3.3 (this
facilitated the isolation of the pp_match bug to an older version perl
on SuSE 8).
Joshua Jensen
- Found bug with the manner in which fwcheck_psad.pl was being called
from psad (improperly passing --no-fw-search-all option even if
FW_SEARCH_ALL was set to "Y").
Mate Wierdl
- Found bug in EMAIL_ADDRESSES format (psad needed to allow addresses
separated by commas).
- Submitted patch for new init-scripts directory for psad.spec file.
- Contributed patch for building the psad RPM on x86_64 platforms.
Stefan (unknown)
- Sugggested permissions fix for world readable files in /var/log/psad.
David Jacobs
- Troubleshooting firewall parsing code, lots of great beta testing
(see: http://www.kungfulinux.com).
Lucas (unknown)
- Suggested fix for init script directory for Slackware Linux systems.
Peter Abraham
- Help testing bugfix for auto_dl code.
- Suggested EMAIL_LIMIT_STATUS_MSG variable to make email limit status
messages optional.
James Lay
- Suggested support for OUTPUT chain in auto-blocking mode.
Yuen Boon Jee
- Found bug in psad init scripts for requiring syslogd config file even
if syslog-ng is installed.
Michael S. Zick
- Bugfix for O_RDONLY open flag when kmsgsd receives a HUP signal.
- Bugfix for psad validation routine that did not accept "0" for a
PORT_RANGE_SCAN_THRESHOLD value.
- Suggested the ability to maintain dedicated chains for the iptables
auto-blocking code.
Nerijus Baliuna
- Suggested ability to ignore entire protocols. The IGNORE_PROTOCOLS
keyword was the result.
- Suggested adding various psad docs (CREDITS, ChangeLog, INSTALL,
etc.) to be installed by the psad rpm
- Suggested the ability to have psadwatchd not send emails even if psad
dies and has to be restarted.
Michael Hadjimichael
- Bug report for syslog format that does not necessarily have the
"kernel:" tag.
Blair Zajac
- Submitted patch to not install perl modules in that are already
installed in the system perl lib tree (this was originally submitted
as a patch for fwknop).
- Found bug with perl module file paths and naming convention (this bug
resulted in some modules being needlessly installed). This find was
originally for fwknop.
- Suggested the -O optimization in Makefile (originally suggested for the
fwknop project).
Troy Swaine
- Suggested a command line interface to block IP addresses. The result
is the --fw-block-ip argument.
Najib Bakari
- Pointed out that sendmail is not usually required to run psad. The
result is the alert.conf file with the ALERTING_METHODS keyword,
which also gets referenced by psadwatchd.
Sam Weiss
- Suggested that psad default FW_MSG_SEARCH to "DROP" if no strings are
defined in fw_search.conf.
Francois Marier
- Contributed REAME.SYSLOG content to help troubleshoot psad and syslog.
Nathan Colt
- Suggested customizable email subjects.
Alex Luna
- Suggested ULOG support.
Torkel Hasle
- Suggested the ability to assign danger levels based on ports in
addition to the protocol in auto_dl. Suggested better sweep detection
by calculating scan danger levels over all destinations (i.e. 5 packets
to different destinations should trigger danger level 1).
SiO
- Reported bug with zero masks in auto_dl file.
Jeroen Vermeulen
- Suggested that psad collect and report errors that are returned by
broken iptables commands to the user. This resulted in a redesign of the
IPTables::ChaingMgr module to collect both stdout and stderr from all
iptables commands.
- Found bug where IPTABLES_AUTO_RULENUM misled the user into thinking that
it governed where the jump rule into a custom chain is added within the
calling chain. This resulted in the IPT_AUTO_CHAIN{n} variables being
updated to support the rule position for both the jump rule and any new
rules within the chain.
Adam Mottershead
- Suggested the ability to disable psad email alerts about auto-blocking
events.
Richard B\351neyt
- Suggested syslog-ng enhancement to allow a custom source path for
/proc/kmsg to be defined for the psadfifo file.
Philip Lawrence
- Contributed patch to fix module path import bug. This resulted in the
psad-2.0.1 release.
Stefano Harding
- Reported bug that caused psad to not acquire iptables data on systems
running syslog-ng when there is no "source" definition for /proc/kmsg.
Aki Tuomi
- Reported bug where iptables might report '0' instead of 'all' for the
protocol under the -nL output.
pyllyukko
- Contributed the psad.SlackBuild script for building psad on Slackware
systems.
- Suggested that the psad.spec file respect the %_initrddir RPM macro.
- Suggested configurable syslog facility and priority settings.
- Contributed a suspicious iptables log message that contained a broken
set of TCP options. This exposed a bug where psad would consume all
available memory on the system and would have to be killed. The result
is an additional check to ensure that the length fields parsed from TCP
options are greater than one byte; otherwise, the TLV encoding doesn't
work out properly.
Christian Lyra
- Found off-by-one error in number of email alerts that are reported under
--Status output.
James Neff
- Provided solution for getting psad to run in Fedora 8 systems by
pointing psad at the /etc/rsyslog.conf file.
Franck Joncourt
- Performed analysis of locale settings for fwknop installer and suggested
using the LC_ALL environmental variable instead of the LANG variable
(which is superseded by LC_* vars).
- Suggested moving dependencies into the deps/ directory to build a common
architecture for bundling the cipherdyne.org projects for Debian.
- Submitted patches for documentation fixes in various psad man pages.
- Submitted patch to fix missing check against the 'mail' command for the
fwcheck_psad.pl script.
- Submitted patch to fix a bug where local server ports were not reported
correctly under netstat parsing.
- Submitted patch to correct mail binary usage to redirect stderr.
- Submitted patch to close stdout, stderr, and stdin when running as a
daemon.
- Added --Override-config feature so that alternate configuration files
can be specified on the command line to override configuration variables
in the standard /etc/psad/psad.conf file.
- Found psad man page section errors with manpage-alert.
Erik Heidt
- Submitted patch to fix fwsnort sid reporting w.r.t. ending newline
chars.
- Reported iptables log prefix bug where timestamps that include spaces
where not being excluded even when IGNORE_KERNEL_TIMESTAMP is set to
"Y".
Andrew Kaplan
- Reported the inability of an older version of the bundled whois client
to query the whois information associated with certain IP addresses.
Updating to whois-4.7.26 solved the problem.
j.bakshi
- Reported a bug where IPT_SYSLOG_FILE was not being honored in -A
(analyze) mode.
Steve B
- Submitted patch to fix a bug in the start() function in the Gentoo init
script which caused psad to not be started and the error "* ERROR: psad
failed to start" to be generated.
Miroslav Grepl
- Contributed policy files to make psad compatible with SELinux. The
files are located in a new "selinux" directory in the
psad sources.
Stephen Nims
- Reported 'Date::Calc::Decode_Month(): argument is not a string at
/usr/sbin/psad line 1103' bug. This affected DShield processing and a
few other areas.
Dan A. Dickey
- Submitted a patch to allow psad to use the "ip" command from the iproute2
tools to acquire IP addresses from local interfaces. Dan's description
is as follows: "...A main reason for doing this is in the case of multi-
homed hosts. ifconfig sets these up on an interface using aliases,
iproute2 does not. So, for a multi-homed interface (eth0 with multiple
addresses), ifconfig -a only shows the first one configured and not the
rest. ip addr shows all of the configured addresses...".
Graham Murray
- Reported a bug where 8-bit data included in some whois output causes mail
delivery problems with the following error:
<<< 554 5.6.1 Eight bit data not allowed
554 5.0.0 Service unavailable
The fix for this problem was the addition of the ENABLE_WHOIS_FORCE_ASCII
functionality.
Dean Takemori
- Reported a condition where whois lookups were being calculated always on
the source IP of suspicious traffic even if the source IP's were on
internal directly connected networks (frequently on RFC 1918 address
space). This report led to a change where whois lookups are now done
against non-local IP addresses by default (see the ENABLE_WHOIS_LOCAL
variable).
Lukas Baxa
- Reported bug for ICMP packet handling where psad would incorrectly
interpret ICMP port unreachable messages as UDP packets because the UDP
specifics are included in the iptables log message.
@pyllyukko
- Suggested --install-root for the install.pl script so that psad can be
installed in a directory specified by the user.
- Suggested the ability to have install.pl read answers to queries from a
file in the filesystem in order to support easy automated installs of
psad.
Kat
- Reported 'Could not resolve sub-var: INSTALL_ROOT to a value' error in
the legacy kmsgsd daemon for psad-2.2.
Gregorio Narvaez
- Reported a NetAddr::IP usage bug in "-A --analysis-fields" mode with IP
searches.
Pui Edylie
- Reported a problem where psad could not map an fwsnort log message back
to the corresponding Snort 'msg' field. Added the FWSNORT_RULES_DIR
variable to have psad read Snort rules from any installed fwsnort
instance.
Oscar Marley
- Suggested configurable auto-blocking timeout values depending on the
danger level that a scan or attack achieves. This resulted in the
implementation of the AUTO_BLOCK_DL*_TIMEOUT variables.
Naji Mouawad
- Suggested the ability to throttle email alerts that psad sends. The
This resulted in the implementation of the EMAIL_THROTTLE variable.
psad-7c4a910/ChangeLog 0000664 0000000 0000000 00000161376 12071203757 0014567 0 ustar 00root root 0000000 0000000 psad-2.2.1 (01/02/2013):
- Added IP protocol scan detection (nmap -sO). A new psad.conf variable
PROTOCOL_SCAN_THRESHOLD defines the minimum number of different IP
protocols (default = 5) that must be scanned before an alert is
triggered.
- Added detection for Topera IPv6 scans when --log-ip-options is used in
the ip6tables logging rule. When this option is not used, the previous
psad-2.2 release detected Topera scans. An example TCP SYN packet
generated by Topera when --log-ip-options is used looks like this (note
the series of empty IP options strings "OPT ( )":
Dec 20 20:10:40 rohan kernel: [ 488.495776] DROP IN=eth0 OUT=
MAC=00:1b:b9:76:9c:e4:00:13:46:3a:41:36:86:dd
SRC=2012:1234:1234:0000:0000:0000:0000:0001
DST=2012:1234:1234:0000:0000:0000:0000:0002 LEN=132 TC=0 HOPLIMIT=64
FLOWLBL=0 OPT ( ) OPT ( ) OPT ( ) OPT ( ) OPT ( ) OPT ( ) OPT ( )
OPT ( ) OPT ( ) PROTO=TCP SPT=61287 DPT=1 WINDOW=8192 RES=0x00 SYN
URGP=0
- Bug fix in --Analyze mode when IP fields are to be searched with the
--analysis-fields argument (such as --analysis-fields "SRC:1.2.3.4").
The bug was reported by Gregorio Narvaez, and looked like this:
Use of uninitialized value $_[0] in length at
../../blib/lib/NetAddr/IP/UtilPP.pm (autosplit into
../../blib/lib/auto/NetAddr/IP/UtilPP/hasbits.al) line 126.
Use of uninitialized value $_[0] in length at
../../blib/lib/NetAddr/IP/UtilPP.pm (autosplit into
../../blib/lib/auto/NetAddr/IP/UtilPP/hasbits.al) line 126.
Bad argument length for NetAddr::IP::UtilPP::hasbits, is 0, should be
128 at ../../blib/lib/NetAddr/IP/UtilPP.pm (autosplit into
../../blib/lib/auto/NetAddr/IP/UtilPP/_deadlen.al) line 122.
- Added --stdin argument to allow psad to collect iptables log data from
STDIN in --Analyze mode. This makes it easier to run an iptables logs
through psad from arbitrary files like so:
# grep "IN=.*OUT=" /var/log/kern.log | psad -A --stdin
- Added the ability to acquire Snort rule 'msg' fields from fwsnort if
it's also installed. A new variable FWSNORT_RULES_DIR tells psad where
to look for the fwsnort rule set. This fixes a problem reported by Pui
Edylie to the psad mailing list where fwsnort logged an attack that psad
could not map back to a descriptive 'msg' field.
- Added the ability to set per-danger level timeouts when psad is
configured to run in auto-blocking mode. These timeouts are implemented
with new AUTO_BLOCK_DL*_TIMEOUT variables - one for each of the five
possible danger levels that may be assigned to a scanning IP address.
- Added the ability to throttle emails generated by psad via a new
EMAIL_THROTTLE variable which is implemented as a per-IP threshold. That
is, if EMAIL_THROTTLE is set to "10", then psad will only send 1/10th as
many emails for each scanning IP as it would have normally.
psad-2.2 (02/20/2012):
- Added support for detection of malicious traffic that is delivered via
IPv6. This is accomplished by parsing ip6tables log messages - these are
in a slightly different format than the iptables log messages. Here is
an example:
Mar 17 13:39:13 linux kernel: [956932.483644] DROP IN=eth0 OUT=
MAC=00:13:46:3a:41:36:00:1b:b9:76:9c:e4:86:dd
SRC=2001:0db8:0000:f101:0000:0000:0000:0002
DST=2001:0db8:0000:f101:0000:0000:0000:0001 LEN=80 TC=0 HOPLIMIT=64
FLOWLBL=0 PROTO=TCP SPT=50326 DPT=993 WINDOW=5760 RES=0x00 SYN URGP=0
Detection of malicious IPv6 traffic can be disabled via a new
ENABLE_IPV6_DETECTION config variable.
- For ICMP6 traffic, added protocol validation for ICMP6 type/code
combinations.
- Replaced Net::IPv4Addr with the excellent NetAddr::IP module which has
comprehensive support for IPv6 address network parsing and comparisons.
- Added a new test suite in the test/ directory to validate psad run time
operations (scan detection, signature matching, and more). To support
this, a new '--install-test-dir' option was added to the install.pl
script. Once this is executed, the test suite can be run via the
test-psad.pl script in the test/ directory.
- Added a new MAX_SCAN_IP_PAIRS config variable to allow psad memory usage
to be constrained by restricting the number of unique IP pairs that psad
This is useful for when psad is deployed on systems with little memory,
and is best utilized in conjunction with disabling ENABLE_PERSISTENCE so
that old scans will also be deleted (and thereby making room for tracking
new scans under the MAX_SCAN_IP_PAIRS threshold).
- Bug fix for 'qw(...) usage as parenthesis' warnings for perl > 5.14
- Bug fix that caused psad to emit the following:
Undefined subroutine &main::LOG_DAEMON called at ./psad line 10071.
This problem was noticed by Robert and reported on the psad mailing list.
- Added --install-root to the install.pl script so that psad can be
installed in a directory specified by the user as opposed to the normal
system default. This was a suggestion from @pyllyukko.
- Added PERL5LIB env variable usage to the install.pl script so that module
installs can reference the current install path.
- Updated to the latest p0f signatures from OpenBSD.
- Altered the 'ET MALWARE Bundleware Spyware CHM Download' Snort rule in
the bundled Emerging Threats rule set to make sure that ClamAV does not
flag on the pattern "mhtml\:file\://" which is associated with the
following ClamAV signature:
$ grep Exploit.HTML.MHTRedir-8 main.ndb
Exploit.HTML.MHTRedir-8:3:*:6d68746d6c3a66696c653a2f2f{1-20}2168
An analysis of this issue was posted here:
http://www.cipherdyne.org/blog/2010/08/22.html
- Bug fix for ICMP packet handling where psad would incorrectly interpret
ICMP port unreachable messages as UDP packets because the UDP specifics
are included in the iptables log message. This bug was first reported by
Lukas Baxa to the Debian maintainers and was followed up by Franck
Joncourt:
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=596240
An example ICMP log message that exposed the bug is included below:
Sep 8 18:04:26 baxic kernel: [28241.572876] IN_DROP IN=wlan0
OUT= MAC=00:1a:9f:91:df:ae:00:21:27:e8:0a:a0:08:00
SRC=10.0.0.138 DST=192.168.1.103 LEN=96 TOS=0x00 PREC=0xC0 TTL=254
ID=63642 PROTO=ICMP TYPE=3 CODE=3
[SRC=192.168.1.103 DST=10.0.0.138 LEN=68 TOS=0x00 PREC=0x00 TTL=0
ID=22458 PROTO=UDP SPT=35080 DPT=33434 LEN=48 ]
- Updated the bundled whois client to 5.0.6.
- Removed the ExtUtils::MakeMaker RPM build requirement from the psad.spec
file. This is a compromise which will allow the psad RPM to be built
even if RPM dosen't or can't see that ExtUtils::MakeMaker is installed -
most likely it will build anyway. If it doesn't, there are bigger
problems since psad is written in perl. If you want to build the psad
RPM with a .spec file that requires ExtUtils::MakeMaker, then use the
"psad-require-makemaker.spec" file that is bundled in the psad sources.
- Switched to git from svn - comprehensive psad development history can
can acquired through gitweb:
http://www.cipherdyne.org/cgi-bin/gitweb.cgi?p=psad.git;a=summary
or through git itself:
$ git clone http://www.cipherdyne.org/git/psad psad.git
- Updated to IPTables::ChainMgr 1.2 and IPTables::Parse 1.1 in the deps/
directory.
- In the /var/log/psad// directories, whois information is stored in
the _whois files, the IP in the filename was included as a
destination IP under the psad -S output. This has been fixed. Here is
an example of the invalid output:
[+] IP Status Detail:
SRC: 123.123.123.221, DL: 2, Dsts: 2, Pkts: 1, Unique sigs: 1,
Email alerts: 1
DST: 1.2.3.4, Local IP
Scanned ports: TCP 1433, Pkts: 1, Chain: INPUT, Intf: eth0
Signature match: "MISC Microsoft SQL Server communication attempt"
TCP, Chain: INPUT, Count: 1, DP: 1433, SYN, Sid: 100205
DST: 123.123.123.221
- By default the install.pl script records user answers to installation
queries so they can be used to install psad in an automated fashion later.
A new option --Use-answers makes this possible. This feature was requests
by @pyllyukko.
psad-2.1.7 (07/14/2010):
- (Dan A. Dickey) Added the ability to use the "ip" command from the
iproute2 tools to acquire IP addresses from local interfaces. Dan's
description is as follows: "...A main reason for doing this is in the
case of multi-homed hosts. ifconfig sets these up on an interface using
aliases, iproute2 does not. So, for a multi-homed interface (eth0 with
multiple addresses), ifconfig -a only shows the first one configured and
not the rest. ip addr shows all of the configured addresses...".
- Added ENABLE_WHOIS_FORCE_ASCII to replace any non-ascii characters in
whois data (which is common with whois lookups against Chinese IP
addresses for example) with the string "NA". This option is disabled by
default, but can be useful if errors like the following are seen upon
receiving an email alert from psad:
<<< 554 5.6.1 Eight bit data not allowed
554 5.0.0 Service unavailable
- Updated psad to issue whois lookups against IP addresses that are not
directly connected to the local system. This is useful for example when
an internal system is scanning an external destination system, and the
scan is logged in the FORWARD chain. Issuing whois lookups on the
internal system (frequently on RFC 1918 address space) is not usually
very useful, but issuing the whois lookup against the destination system
gives much more interesting data. This feature can be disabled with the
new ENABLE_WHOIS_FORCE_SRC_IP variable.
psad-2.1.6 (07/09/2010):
- Bug fix for Decode_Month() calls used to handle date formats and ensure
proper month handling for iptables log message time stamps. This bug
caused psad to die in some cases, and the specific error on the console
in --debug mode was:
Date::Calc::Decode_Month(): argument is not a string at \
/usr/sbin/psad line 1103, line 2.
- (Franck Joncourt) Added --Override-config feature so that alternate
configuration files can be specified on the command line to override
configuration variables in the standard /etc/psad/psad.conf file.
- (Franck Joncourt) Submitted patches to fix stderr redirection for the
usage of the mail binary, and to close stdout, stdin, and stderr when
running psad as a daemon.
psad-2.1.5 (02/20/2009):
- (Miroslav Grepl) Contributed policy files to make psad compatible with
SELinux. The files are located in a new "selinux" directory in the
psad sources.
- Bug fix for local server ports not reported correctly under netstat
parsing (Franck Joncourt).
- (Steve B) Submitted patch to fix a bug in the start() function in the
Gentoo init script which caused psad to not be started and the error
"* ERROR: psad failed to start" to be generated.
- Bug fix when ENABLE_SYSLOG_FILE is enabled to run a preliminary regex
match on each syslog message because kmsgsd is not running and therefore
has not gone through the kmsgsd tests for a properly structured iptables
message.
- Updated IPTables::Parse to 0.7.
- Updated IPTables::ChainMgr to 0.9.
psad-2.1.4 (08/21/2008):
- Restructured perl module paths to make it easy to introduce a "nodeps"
distribution of psad that does not contain any perl modules. This
allows better integration with systems that already have all necessary
modules installed (including the IPTables::ChainMgr and IPTables::Parse
modules). The main driver for this work is to make all cipherdyne.org
projects easily integrated with distributions based on Debian, and
Franck Joncourt has been instrumental in making this process a reality.
All perl modules are now placed within the "deps" directory, and the
install.pl script checks to see if this directory exists - a separate
psad--nodeps tarball will be distributed without this directory.
The Debian package for psad can then reference the -nodeps tarball, and
a new "psad-nodeps.spec" file has been added to build an RPM from the
psad sources that does not install any perl modules.
- Updated to use the normal system whois client if the /usr/bin/whois_psad
path does not exist, and moved the whois/ directory into the deps/
directory. This removes /usr/bin/whois_psad as a strict dependency.
- Bugfix to honor the IPT_SYSLOG_FILE variable in --Analyze-msgs mode.
- Switched from the deprecated bleeding-all.rules file to the new
emerging-all.rules available from Matt Jonkman at Emerging Threats
(http://www.emergingthreats.net).
psad-2.1.3 (06/07/2008):
- Updated to enable IPT_SYSLOG_FILE by default. This is a relatively
important change since it changes the method of acquiring iptables log
data from reading it out of named pipe from syslog to just parsing the
/var/log/messages file. This implies that kmsgsd does not have to run,
and that it is much easier to ensure that psad actually receives
iptables log messages. The most complex and error prone aspect of psad
in the past has been the reconfiguration of the various syslog daemons
out there (which have very different configuration syntax and features)
to write kern.info messages to the /var/lib/psad/psadfifo named pipe.
- Updated to version 4.7.26 of the whois client from Marco d'Itri. This
allows whois records for some addresses (such as 116.125.35.98, which
which was scanning a system running psad but could not be identified
under the older whois client) to be properly queried.
- Updated to Bit::Vector 6.4 from 6.3.
- Updated to Date::Calc 5.4 from 5.3.
- Updated to Storable 2.18 from 2.16.
psad-2.1.2 (04/03/2008):
- Bugfix to not include kernel timestamps in iptables log prefixes that
contain spaces like "[ 65.026008] DROP" (bug reported by Erik Heidt).
- Bugfix to skip non-resolved IP addresses (bug reported by Albert Whale)
- Better p0f output in --debug mode to display when a passive OS
fingerprint cannot be calculated based on iptables log messages that
include tcp options (i.e., with --log-tcp-options when building a LOG
rule on the iptables command line).
psad-2.1.1 (01/25/2008):
- Added a new feature whereby psad can acquire iptables log data just by
parsing an existing file (/var/log/messages by default) that is written
to by syslog. By default, psad acquires iptables log data from the
/var/log/psad/fwdata file which is written to by kmsgsd, but on some
systems, having syslog communicate log data to kmsgsd can be problematic
since syslog configs and external factors such as Apparmor and SELinux
can play a role here. This new feature is controled by two new
configuration variables "ENABLE_SYSLOG_FILE" (to enable/disable the
feature) and "IPT_SYSLOG_FILE" to specifiy the path to the file to
parse.
- Better installation support for various Linux distributions including
Fedora 8 and Ubuntu. The current runlevel is now acquired via the
"runlevel" command instead of attempting to read /etc/inittab (which
does not even exist on Ubuntu 7.10), and there are new command line
arguments --init-dir, --init-name, and --runlevel to allow the init
directory, init script name, and the runlevel to be manually specified
on the install.pl command line.
- Updated psad to automatically handle situations where the either the
/var/log/psad/fwdata file or the /var/log/messages file (whichever
syslog is writing iptables log messages to) gets rotated. The
filehandle is closed and reopened if the file shrinks or if the inode
changes. This strategy is borrowed from how the fwknop project deals
with the filesystem packet capture file.
- Minor bugfix to generate syslog message when restarting a psad process.
- Updated install.pl to set the LC_ALL environmental variable to "C"
This should address some issues with installing psad on non-English
locale systems.
- Updated install.pl to be compatible with the rsyslog daemon, which is
commonly installed on Fedora 8 systems.
psad-2.1 (10/19/2007):
- Changed EMAIL_LIMIT model to apply to scanning source addresses only
instead of also factoring in the destination address. The original
src/dst email limit behavior can be restored by setting a new variable
"ENABLE_EMAIL_LIMIT_PER_DST" to "Y".
- Added the patches/iptables-1.3.8_LOG_prefix_space.patch file which can
be applied to the iptables-1.3.8 code to enforce a trailing space
character before any log prefix when a LOG rule is added. This ensures
that the user cannot break the iptables syslog format just by forgetting
to include a space at the end of a logging prefix.
- Bugfix to ensure that parsing TCP options does not descend into an
infinite loop in some some circumstances with obscure or maliciously
constructed options. Also added syslog reporting for broken options
lengths of zero or one byte (the minimum option length is two bytes to
accomodate the TLV encoding).
- Bugfix to enforce the usage of --CSV-fields in --gnuplot mode.
- Implemented --get-next-rule-id so that it is easy to assign a new rule
ID to a new signature in the /etc/psad/signatures file.
- Updated to just call die() if GetOpt fails; this allows erroneous usage
of the command line to display informative error messages more clearly.
psad-2.0.8 (07/27/2007):
- Added --gnuplot mode so that psad can output data that is suitable for
plotting with gnuplot. All output produced in this mode is integer data
with the exception of date stamps that are derived from iptables syslog
messages.
- Added the ability to negate match conditions on fields specified with
the --CSV-fields argument by prepending the string "not" (which plays
more nicely with shells like bash than a character like "!"). For
example, to graph all packet data in --gnuplot or --CSV modes that
originates from the 11.11.0.0/16 subnet and is not destined for port
80, the following argument does the trick:
--CSV-fields "src:11.11.0.0/16 dp:not80"
- In --gnuplot mode, added the ability to generate the count for a CSV
field instead of the field itself. Supported modes are an absolute
count (:count) , and a unique count (:uniqcount). This
is useful to plot graphs of source IP vs. the number unique ports for
example. Also added the ability to count iptables log fields over
various time scales (minutes, hours, and days) with the following
switches: :countday, :counthour, :countmin.
- In --gnuplot mode, added the ability to specify the view coordinates
for 3D graph viewing with --gnuplot-view.
- Added the Storable-2.16 module along with the --use-store-file argument
so that in --gnuplot mode the Gnuplot data can be stored on disk and
retrieve quickly. This eliminates a large performance bottleneck when
Gnuplot configuration directives are tweaked while the same graph is
generated multiple times.
- Added --gnuplot-template so that a template file can be used for all
Gnuplot directives (usually psad creates the .gnu file based on the
--gnuplot command line arguments).
- Added --gnuplot-grayscale to generate graphs without the default red
color for graph points.
- Bugfix for regular expressions not being imported correctly from within
the --CSV-fields argument.
- Added --analysis-fields so the iptables log messages that are parsed in
-A mode can be restricted to those that meet certain criteria. For
example, to restrict the analyze mode to process packets with a source
address of 192.168.10.1, use this command:
psad -A --analysis-fields "src:192.168.10.1"
- Added --plot-separator to allow the format of plot data (either in
--gnuplot or --CSV modes) to be influenced by the user.
- Added the ability to configure the syslog facility and priority via the
psad.conf file (see the SYSLOG_FACILITY and SYSLOG_PRIORITY variables).
- Updated psad.spec file to respect the %_initrddir RPM macro.
psad-2.0.7 (05/28/2007):
- Bugfix to define a custom 'source' definition for syslog-ng daemons -
this fixes a problem on SuSE systems where the existing syslog-ng
reconfig caused the daemon to not start.
- Bugfix to allow specific signatures to be ignored by setting SID values
of zero in /etc/psad/snort_rule_dl.
- Added -X command line argument to allow the user to delete any psad
chains (in auto-response mode). This is a synonym for the iptables -X
command line argument.
psad-2.0.6 (03/24/2007):
- Better integration with fwsnort; psad signature match syslog messages
and email alerts now include the fwsnort rule number (for fwsnort
version 0.9.0 and greater) and chain information.
- Added the Snort bleeding-all.rules signature file from the Bleeding
Snort project (see http://www.bleedingsnort.com).
- Bugfix to allow interfaces that have IP aliases.
- Added uname, ifconfig, and syslog process information to --Dump-conf
output (this can help diagnose various runtime issues).
- Changed the --Lib-dir command line argument to --lib-dir, and added
--List (similar to iptables) to list the psad auto-blocking chain rules.
- Added psad.SlackBuild script contributed by pyllyukko for building psad
on Slackware systems. It uses the Cipherdyne cd_rpmbuilder script to
first build and RPM, and then uses it to build a Slackware package.
psad-2.0.5 (03/01/2007):
- Consolidated all configuration variables into the /etc/psad/psad.conf
file. The kmsgsd.conf, psadwatchd.conf, alert.conf, and fw_search.conf
files were all removed since the daemons just reference the psad.conf
now. Updated install.pl to archive and remove these files if they
exist from a previous psad installation.
- Bugfix to account for iptables -nL output where the protocol may be
reported as "0" instead of "all".
- Added a function safe_malloc() for kmsgsd.c and psadwatchd.c to ensure
that a single API is used to perform a NULL check on heap-allocated
memory.
- Bugfix to ensure that the psad_ip_len signature matching keyword is
checked withing match_snort_ip_keywords() so that it applies to all
protocol packets. This fixes a bug that would cause the "PSAD-CUSTOM
Nachi worm reconnaisannce" signature to fire on normal ICMP packet log
messages.
- Added version and Subversion file revision numbers to die and warn
messages that are written to /var/log/psad/errs/. This helps when
trying to track these messages down to a specific file revisions when
psad is being upgraded on the local system.
- Added version and Subversion file revision numbers to --Dump-conf
output.
- Minor update to allow --fw-dump to be used on the command line without
also having to use the -D argument.
- Updated the default_log() function in the IPTables::Parse module to
handle iptables policies that were dumped with -v, such as when
--Dump-conf is used.
psad-2.0.4 (01/27/2007):
- Added Snort rule matches to syslog alerts. Multiple matches can be
controlled with new configuration variables in psad.conf:
ENABLE_SIG_MSG_SYSLOG, SIG_MSG_SYSLOG_THRESHOLD, and
SIG_SID_SYSLOG_THRESHOLD.
- Bugfix to include scanned UDP port ranges in syslog alerts.
- Bugfix to parse SEQ and ACK iptables log message fields (requires
--log-tcp-sequence on the iptables command line). This allows the ipEye
signature to work.
- Added --debug-sid to allow a specific Snort rule to be debugged while
psad runs it through its detection engine. A consequence of this is
that the -d command line argument must be spelled out, i.e. "psad
--debug".
- Bugfix to allow logging prefixes to omit trailing spaces. This is a bug
in the iptables logging format to allow this in the first place, but
before this gets fixed psad needs to compensate.
- Bugfix for syslog-ng init script path in install.pl.
- Bugfix to include a "source" definition for /proc/kmsg if not already
defined for syslog-ng daemons.
- Minor memory handling bugfixes discovered by valgrind the excellent
Valgrind project: http://www.valgrind.org
psad-2.0.3 (12/31/2006):
- Removed Psad.pm perl module and kmsgsd.pl and psadwatchd.pl scripts.
This is a major change that allows psad to be more flexible and
completely derive its config from the psad.conf file and from the
command line. In the previous scheme, psad imported its config with a
function within Psad.pm, and this required that psad imported the Psad
perl module before reading its config. A consequence was that the
PSAD_LIBS_DIR var could not be specified usefully within the config
file.
- Added the ability to recursively resolve embedded variables from *.conf
files (with a limit of 20 resolution attempts).
- Added IGNORE_KERNEL_TIMESTAMP so that Linux distros that add a timestamp
to all kernel messages (Ubuntu for example) can be ignored.
- Consolidated code to import data out of /var/log/psad/ directories
with code to display status and analysis output (-S and -A).
Essentially the %scan hash is built by the filesystem data import
routine and the remainder of the code references this single data
structure.
psad-2.0.2 (12/23/2006):
- Added the ability to download the latest signatures from cipherdyne.org
in install.pl.
- Added the cd_rpmbuilder script to make it easy to build RPM's out of
CipherDyne projects by automatically downloading the project .tar.gz and
.spec files from http://www.cipherdyne.org/.
- Added print statements for @INC array in debug mode so that the user can
see the additional /usr/lib/psad/* directories added by
import_psad_perl_modules().
- Changed Unix::Syslog import strategy from "use" to "require" since the
path is not known until import_psad_perl_modules() gets a chance to
run (psad ran fine without this, but it is more consistent this way).
- Bugfix for not properly including elements of the
@connected_subnets_cidr array.
- IP subnet bugfix to make sure to get the entire subnet in signature
import routine if it is not in CIDR format
- Bugfix to not print an IP addresses in the "top attackers" section that
do not have at least one packet or signature match (for any reason).
- Bugfix to not print more than TOP_IP_LOG_THRESHOLD IP addresses in thet
top attackers section.
- Updated install.pl to reference configuration paths directly from
psad.conf instead of defining them separately. This should fix Debian
bug #403566.
- Added -c argument to install.pl so that the path to a psad.conf file
can be altered from the command line.
- Bugfix to not import any IP from the top_attackers file from a previous
psad run that does not have a /var/log/psad/ directory.
- Added MIN_DANGER_LEVEL to allow all alerts and /var/log/psad/
tracking to be disabled unless an attacker reaches at least this
danger level.
- Added text in install.pl to mention ifconfig parsing for HOME_NET
derivation.
psad-2.0.1 (12/12/2006):
- Added Nachi worm reconnaisannce icmp signature
- Added the psad_ip_len signature keyword to allow the length field in the
IP header to be explicitly tested.
- Bugfix for inappropriately removing some directories in @INC when
splicing in psad perl module paths.
- Switched nf2csv installation path in install.pl to /usr/bin/.
psad-2.0 (12/10/2006):
- Completely refactored the Snort rule matching support in psad. Added
many header field tests with full range matching support. These tests
include the following keywords from Snort: ttl, id, seq, ack, window,
icmp_id, icmp_seq, itype, icode, ip_proto, ipopts, and sameip.
- Refactored all signatures in /etc/psad/signatures to conform to new
signature matching support in this release. There are now about 190
signatures that psad can run directly against iptables logging
messages (i.e. without the help of fwsnort).
- Added the ability to download the latest signatures file from
http://www.cipherdyne.org/psad/signatures with the --sig-update command
line argument to psad.
- Added "MISC Windows popup spam" signature. This allows psad to detect
when attempts are made to send spam via the Windows Messenger service.
- Completely reworked --Status and --Analyze output, signature matches
are included now, along with a listing of top sig matches, top scanned
ports, and top attackers. Also, scan data is not written to
/var/log/psad/ipt_analysis/ before display analysis output in -A mode;
analysis results are displayed much faster this way.
- Added ipEye, Subversion, Kuang2, Microsoft SQL, Radmin, and Ghostsurf
signatures.
- Added 'data in TCP SYN packet' signature.
- Added --CSV mode so that psad can be used to generate comma-separated
value output suitable for the AfterGlow project (see
http://afterglow.sourceforge.net/index.html) for graphical
representations of iptables logs and associated scan data. Also added
nf2csv so that normal users can take advantage of this feature.
- Added emulation of the Snort "dsize" test through the use of the IP
length field for TCP/ICMP signatures, and the UDP length field for UDP
signatures. For SYN packets, TCP options are included so psad
automatically adds 44 bytes (the maximum length for TCP options) so the
dsize test corresponds to the estimated payload length.
- Added the psad_id, psad_dsize, and psad_derived_sids fields for the new
Snort rule support.
- Added the ability to decode IP options, which are included within Snort
rules as the "ipopts" keyword. This functionality requires that the
--log-ip-options command line argument is given to iptables when
building a rule that uses the LOG target.
- Added Snort rules (sids 475, 500, 501, and 502) that detect IP options
usage such as source routing and the traceroute IP option with the new
IP options decoder.
- Enhanced psad email alert output to include sid values that have been
derived from existing Snort rules.
- Added the ability to expand embedded variables within the psad
configuration files. For example, the path to the FW_DATA_FILE is
defined in psad.conf as "$PSAD_DIR/fwdata", which resolves to
/var/log/psad/fwdata when the PSAD_DIR variable is expanded. This
feature allows a consistent set of file paths to easily be defined
instead of using the full path for each file path.
- Better validation of IPT_AUTO_CHAIN{n} variables so that the from_chain
cannot be identical to the to_chain.
- Added dump_config() to psadwatchd.c and kmsgsd.c when compiled with
debugging support.
- Added ENABLE_INTF_LOCAL_NETS to have psad automatically treat all IP
addresses that are part of the local system as belonging to the HOME_NET
for signature matching.
- Added ENABLE_SNORT_SIG_STRICT to have psad exit if there are any
problems found with Snort rules in the /etc/psad/signatures file. If
this feature is disabled (this is the default), then psad generates
syslog warnings for improperly formatted signatures).
- Update to print the number of IP addresses at each danger level in -A
analysis mode. This is useful to get a sense for how long the disk IO
might take to write out all of the /var/log/psad/ipt_analysis/
directories.
- Added code to restart kmsgsd at psad start up if a previous kmsgsd
process is still running and TRUNCATE_FWDATA is set to 'Y' (this is the
default). This probably isn't strictly necessary because kmsgsd is
capable of writing to the fwdata file even if another process truncates
it.
- Added code to recreate the AUTO_IPT_SOCK (/var/run/psad/auto_ipt.sock)
file if some other process happens to delete it out of /var/run/psad/
- Bugfix to allow backwards compatibility with old NOT_USED value
for the HOME_NET variable.
- Bugfix to cleanup any lost blocking rules from the running psad
timeouts (a separate process might have deleted rules from the psad
chains).
- Bugfix to allow iptables log messages to include the PHYSDEV (i.e.
PHYSIN and PHYSOUT) interfaces.
- Updated to read architecture-dependent perl module installation
directory out of /usr/lib/psad (e.g. "/usr/lib/psad/x86_64-linux")
before importing psad perl modules such as IPTables::Parse, etc. These
modules are now imported via "require" after the appropriate
directories have been added to @INC. This allows the RPM files to be
built on one system that builds @INC differently than the system where
psad is actually installed since psad can now compensate for this.
- Added new code to populate the _signature file in each of the
/var/log/psad/ directories with verbose information including the
signature time, sid, protocol, dst port, and packet count.
- Changed --interval to --Interval, and added --interface to allow
psad's detection to be limited to a specific IN interface for the INPUT
and FORWARD chains (or OUT interface for the OUTPUT chain).
- Replaced --status-brief with --status-summary, but changed it so that
only the detailed IP status information is omitted.
- Removed unnecessary --status-sort-dl option.
- Added STATUS_OUTPUT_FILE so the --Status and --Analyze output is
captured instead of just being lost if the output was not piped to
'less' or another similar program.
- Added --restrict-ip so that psad will restrict its attack detection
operations to a specific IP or network.
- Updated psadwatchd.c to parse EMAIL_ADDRESSES out of
/etc/psad/psad.conf to avoid duplication of variables.
- Bugfix to clear old @ipt_config array after receiving a HUP signal.
This bug broke the auto-blocking mode.
- Bugfix for syslog-ng config so that any custom source for /proc/kmsg is
used for the psadfifo path.
psad-1.4.8 (10/15/2006):
- Added the ability to get the auto-blocking status for a specific IP
address in --status-ip mode.
- Bugfix to use the IPT_OUTPUT_FILE and IPT_ERROR_FILE configuration
variables.
- Bugfix to restore "start" functionality in Gentoo init script.
- Added the ability to selectively disable psad auto-blocking emails.
- Added more rigorous IP matching regex from Sebastien J. (contributed
originally for fwknop).
psad-1.4.7 (09/10/2006):
- Completely re-worked IPTables::ChainMgr to support the return of
iptables error messages that are collected via stderr. This is critical
to fixing a bug where psad would sometimes die on an iptables command
but no information would be returned to the user.
- Added the ability to specify the position for both the jump rule into
the psad chains as well as the position for new rules within the psad
chains via the -I argument to iptables. This fixes a bug where the user
was given the impression that the IPTABLES_AUTO_RULENUM would accomplish
this.
- Populated the _debug option in the IPTables::ChainMgr module, and also
added a _verbose option so that the specific iptables commands can
actually be seen as IPTables::ChainMgr functions are called.
- Added code to install.pl to ask the user if a manual restart of syslog
is ok upon an unsuccessful test of the syslog reconfiguration. This
fixes a bug where some syslog daemons might not re-import their
configurations after receiving a HUP signal.
- Bugfix for incorrect config variable name that gated iptables
prerequisite checks.
- Added code to install.pl to update command paths in psad.conf and
psadwatchd.conf if any of the paths are broken (i.e. the local system
does not conform to the default paths). By default this only happens if
the user does not want old configs to be merged, but to override this
use the new --path-update command line argument to install.pl.
- Added the --Skip-mod-install command line argument to install.pl to
allow all perl module installs to be skipped.
- Added the --force-mod-regex command line argument to install.pl to allow
a regex match on perl module names to force matching modules to be
installed.
- Added the logrotate.psad file (contributed by Albert Whale).
psad-1.4.6 (06/13/2006):
- Added ENABLE_AUTO_IDS_REGEX and AUTO_BLOCK_REGEX to allow filtering on
logging prefixes.
- Added code to save DShield email to a file.
- Added IPTABLES_PREREQ_CHECK to allow the administrator to control the
frequency of iptables checks (for auto-block compatibility).
- Added IGNORE_LOG_PREFIXES to allow certain log prefixes to be completely
ignored by psad.
- Added classification.config file from Snort-2.3.3 so that psad can
assign danger levels based upon Snort rule class type. This is useful
when also running fwsnort.
- Added snort_rule_dl to allow specific psad to assign specific danger
level values to particular signatures. This is useful if you want to
do define certain Snort rules as being particularly evil (or not).
Running fwsnort is also necessary to take advantage of this feature.
- Added reference.config so that psad can include reference information in
email alerts that are derived from attacks detected by fwsnort.
- Updated to Snort-2.3.3 signatures.
- Updated to whois-4.7.13.
psad-1.4.5 (01/13/2006):
- Bugfix in IPTables::Parse to allow the limit target to apply to
logging rules.
- Made calls to chain creation and jump rule functions for only every
100 block calls in auto-IDS mode.
- Bugfix to make sure /var/run/psad directory exists at startup since
this directory is removed by some Linux distributions at boot time.
- Bugfix for zero masks in auto_dl; this allows a network of "0.0.0.0/0"
to be specified.
- Added ENABLE_FW_LOGGING_CHECK so that the iptables policy check can be
enabled/disabled easily via psad.conf.
- Enhanced -D output to include "uname -a" and "perl -V" output.
- Added ENABLE_RENEW_BLOCK_EMAILS to allow whether renew emails are sent
for auto-blocked addresses.
psad-1.4.4 (11/27/2005):
- Added MAC address reporting in psad email alerts. This feature is
enabled via a new config keyword "ENABLE_MAC_ADDR_REPORTING".
- Added --fw-rm-block-ip option to allow IP addresses to be removed
from the auto-blocking chains from the command line.
- Updated command line firewall arguments to write commands to the
AUTO_IPT_SOCK domain socket.
- Added the ability to specify ports and port ranges to auto_dl file.
- Added --force-mod-install command line argument to installer to force
perl modules used by psad to be installed within /usr/lib/psad
regardless of whether they already exist in the system perl tree.
- Bugfix in the installer to seek() to the end of the fwdata file
- Bugfix for psad repeatedly trying to remove the same IP address(es)
from the auto-blocking chains.
instead of reading the entire thing into memory.
- Added the ability to truncate the fwdata file via a new configuration
keyword "TRUNCATE_FWDATA" (this is enabled by default).
- Bugfix in auto-blocking mode for deleting AUTO_IPT_SOCK when a HUP
signal is received.
- Bugfix for parsing iptables policies that contain ULOG logging rules
instead of the standard LOG target.
- Removed the smtpdaemon requirement in the RPM because psad might be
configured to not send email alerts.
psad-1.4.3 (09/27/2005):
- Bugfixes for auto-blocking code. Timeouts should be handled
properly, including cached IP addresses in the auto_blocked_iptables
file that are referenced upon psad startup. Communication with the
running psad is performed over a Unix domain socket in --fw-block
mode.
- Bugfix to seek to the end of the fwdata file instead of reading the
entire thing into memory and then looking for newly written logging
messages. This drastically reduces the amount of memory required
by psad.
- Updated to only display psad chains if --verbose is set
- Updated to automatically flush the psad auto-response iptables chains
at start time (subject to a new config keyword "FLUSH_IPT_AT_INIT").
psad-1.4.2 (07/15/2005):
- Dependency bugfixes for mail binary.
- Bugfix for various IGNORE_* keywords not being honored.
- Bugfix for not timing out blocked IP addresses from a previous run.
- Updated to version 0.2 of the IPTables::ChainMgr module.
- Updated to not truncate the fwdata file upon psad startup.
- Added --fw-dump which produces a sanitized (i.e. no IP addresses)
version of the local iptables policy. Also added --fw-include-ips
to (optionally) not sanitize IPs/nets. Note that the 0.0.0.0 and
0.0.0.0/0 IPs/nets are not sanitized since they give no useful
information about specific IPs/nets.
- Added ulogd data collection mode.
- Bugfix for FW_MSG_SEARCH default (at least "DROP" is included now
even if FW_SEARCH_ALL is set to "N").
- Bugfix for non-network address for subnet specified with --fw-block.
- Bugfix for multiple --fw-block IPs/nets.
- Added README.SYSLOG (Francois Marier contributed the content).
- Made email alert prefixes (such as "[psad-alert]") customizable via
psad.conf.
psad-1.4.1 (03/12/2005):
- Updated to Snort-2.3 rules in the snort_rules directory.
- Re-worked syslog installation portion of install.pl. The user will
always be prompted to enter the syslog daemon now, and also added
the --syslog-conf arg to allow the config file path to be specified
on the install.pl command line.
- Bugfix in install.pl for using IP address instead of network address
of directly connected subnets.
- Updated to version 4.6.23 of the whois client.
- Bugfix for distinguishing OPT field associated with --log-tcp-options
vs. --log-ip-options.
- Bugfix for syslog format that may not include the "kernel:" tag.
- Applied patch to only install perl modules that are not already
installed (Blair Zajac).
- Bugfix for the psad version number that is sent in DShield alerts.
- Updated Psad module directory structure to be consistent with current
versions of perl (5.8.x).
- Added IPTables::ChainMgr module.
- Completely re-worked the iptables auto-blocking code to use
IPTables::ChainMgr functions so that auto-generated rules are placed
in chains created by psad.
- Added IPT_AUTO_CHAIN keyword in psad.conf which is used to define the
set of chains to which auto-generated iptables rules are added.
- Added --fw-list-auto to display the contents of psad iptables
chains.
- Added the ability to import an IP into the iptableiptablesocking
chains from the command line with --fw-block-ip. This allows psad to
apply its timeout mechanism against such IPs/nets.
- Added the ability to ignore packets based on input interface with
IGNORE_INTERFACES in psad.conf.
- Re-worked auto_dl code, better hash design and searching function.
- Removed dependency on sendmail command unless DShield alerting is
enabled and a DShield user id is specified.
- Added ALERTING_METHODS keyword in the file alert.conf to allow either
syslog or email alerts (or both) to be disabled. Psad and psadwatchd
reference this file.
psad-1.4.0 (11/26/2004):
- Added p0f-style passive OS fingerprinting through the use of the OPT
field in iptables log messages (which is only logged through the use
of the --log-tcp-options command line arg to iptables).
- Bugfix for iptables log messages that include tcp sequence numbers
(see the iptables --log-tcp-sequence command line argument).
- Bugfix for O_RDONLY open flag when kmsgsd receives a HUP signal.
psad-1.3.4 (10/17/2004):
- Bugfix for init script directory on Slackware systems.
- Bugfix for null prefix counters.
- Added --whois-analysis argument since whois lookups are now disabled
by default when running in analysis (-A) mode.
- Updated psad_init() to rework setup() and import orderings vs.
--fw-analyze and --Benchmark modes.
- Added bidirectional iptables auto-blocking support for all chains
except for the INPUT and OUTPUT chains.
- Better syslog message support when run in auto-blocking mode.
- Added iptables auto-block rules section to --Status output.
- Added init script for Fedora systems.
- Added default_log() function to IPTables::Parse. This function
parses user defined chains in an effort to find default logging
rules.
- Added EMAIL_LIMIT_STATUS_MSG to control whether or not psad sends a
status email when the PSAD_EMAIL_LIMIT threshold has been reached by
an IP address.
- Added ENABLE_SCAN_ARCHIVE to control whether or not psad archives old
scan data within /var/log/psad/scan_archive at start time.
psad-1.3.3 (09/09/2004):
- Fixed __WARN__ and __DIE__ exception handlers so that they
reference global message variables.
- Fixed auto danger level assignments. Network auto assignments as
well as per-protocol assignments work now.
- Added SYSLOG_DAEMON variable to define which syslog daemon is running
on the underlying system instead of just guessing.
- Added the ability to ignore both ranges and specific ports/protocols
with a new variable IGNORE_PORTS in psad.conf.
- Bugfix to make sure email addresses are separated by spaces when
Psad::sendmail() is called.
- Bugfix for ipt_prefix counters not being parsed correct at import
time.
- Removed exclude_auto_ignore_ip() since this function was made
unnecessary by newly rewritten auto-assign code.
- Bugfix for Text::Wrap calls in install.pl uninstall() routine.
- Bugfix for using --no-fw-search-all even when FW_SEARCH_ALL is
set to "Y".
- Removed extraneous ".." and "**" chars from syslog messages, and
updated to use [+] prefix strings.
- Moved init scripts into init-scripts directory within source tree.
- Removed dependency on Bit::Vector (psad does not seem to make use
of any Date::Calc functions that require it).
- Wrapped copy() and move() calls with "or die()" to make them
safer in install.pl.
- Added check for existing psad process in install.pl.
- Updated to a new psad email alert subject format. Prefixes of
"[psad-alert]", "[psad-error]", and "[psad-status]" are used now.
- Permissions fixes with umask() setting in /var/log/psad, permissions
fixes for files in /etc/psad at install time.
psad-1.3.2 (06/25/2004):
- Removed FW_MSG_SEARCH from psad.conf, and created a new config
file "fw_search.conf" that both psad and kmsgsd use to get the
FW_MSG_SEARCH definition(s).
- Added default mode of parsing all iptables messages instead of
just those that contain specific search strings. A new config
variable "FW_SEARCH_ALL" was added to fw_search.conf that
controls this mode.
- Updated psad and kmsgsd so that multiple firewall search strings
can be specified through multiple FW_MSG_SEARCH variables in
fw_search.conf.
- Added iptables chain and logging-prefix tracking for current
scan interval in email alerts.
- Added protocol-specific auto-danger level assignments.
- Added total scan source and destination IP address counters in
--Status output.
- Added number of email alerts sent and OS guess in default
--Status output. The output is getting wide now, so there is
also a new option --status-brief that will remove the alerts
sent and OS guess columns.
- Added getopt() command line arg parsing to kmsgsd with two new
options "-c" (for config file path) and "-k" (for fw_search.conf
path).
- Made iptables parsing code into its own script "fwcheck_psad"
that gets called by psad.
- Added Dshield stats summary to --Status output.
- Bugfix for auto-ignore IP addresses and networks being missed.
- Made parsing of ifconfig output language independent (should
handle French now for example).
- Removed "psad_" prefix on files psad_signatures, psad_auto_ips,
psad_posf, and psad_icmp_types in /etc/psad/.
- Updated to version 4.6.14 of the whois client.
psad-1.3.1 (12/25/2003):
- Added the ability to import /var/log/psad/ directories
back into memory so scan data remains persistent across
psad restarts or system reboots.
- Added --Analyze-msgs to run psad in analysis mode against an
iptables logfile (/var/log/psad/fwdata by default). The logfile
path can be changed with --messages-file.
- Added icmp type and code validation against RFC 792.
- Bugfix for being too strict with FW_MSG_SEARCH.
- Added port ranges for tcp and udp scans in /_packet_ctr.
- Added /_start_time and /os_guess.
- Bugfix for missing --no-signatures code.
- Updated to Snort-2.1 signatures.
psad-1.3 (11/30/2003):
- Replaced all signatures in psad_signatures with updated snort
rules.
- Added support for source and destination ip addresses in
signature matching code. A new variable "HOME_NET" makes this
possible.
- Added support for the iptables output chain.
- Added chain tracking for all signatures.
- Replaced match_fastsigs() with two new routines for tcp and
udp signature matching that don't autovivify hash keys.
- Removed support for ipchains.
- Added support for metalog.
- Removed all "Undefined Code" signatures from psad_signatures.
- Re-worked %auto_blocked_ips hash and corresponding blocking
routines. This (hopefully) fixes a restart bug seen on older
systems such as those that are still running versions of perl
less than 5.6.
- Re-worked firewall policy parsing routines. Chains that have
a default policy of DROP are handled properly now.
- Bugfix for missing NULL char in kmsgsd.c.
- Updated scan alerting format. Put current interval protocol
status before source and destination addresses.
- Buffer overflow fix in kmsgsd.c for size of buf[MAX_LINE_BUF]
buffer in read() call.
- Added --no-kmsgsd option to aid in psad --debug mode.
psad-1.2.4 (10/15/2003):
- Added danger level to subject line in email alerts.
- Removed diskmond altogether since psad now handles disk space
thresholds directly. This allows filehandles to be handled
properly.
- Added auto_block_ignore_ip() to prevent 0.0.0.0, 127.0.0.1,
and local interface ips from being included in auto blocking
routines.
- Added Bit::Vector module to stop installation warnings from
Date::Calc.
- Made get_local_ips() called periodically since local addresses
may change (dhcp, etc.).
- Added installation code and init script for Gentoo Linux.
- Bugfix for INIT_DIR in uninstall() routine in install.pl.
- Bugfix for auto-blocking loop after timeouts are hit.
- Added --status-dl [N] to display status information only for
those scans that reach at least [N].
psad-1.2.3 (09/12/2003):
- Added interface tracking for scans.
- Bugfix for not opening /etc/hosts.deny the right way in
tcpwr_block().
- Bugfix for psadfifo path in syslog-ng config.
- Better format for summary stats section in email alerts.
- Bugfix for INIT_DIR path on non-RedHat systems.
- Bugfix for gzip path.
- Make Psad.pm installed last of all perl modules installed
by psad.
- Added additional call to incr_syscall_ctr() in psadwatchd.c
psad-1.2.2 (08/24/2003):
- psad is finally available as an RPM package.
- Added chain tracking for iptables.
- Added chain counts to --Status output.
- Bugfix for psad not taking into account multiple scan
destinations.
- Reworked auto-blocking code for both tcpwrappers and
iptables. Lines added to /etc/hosts.deny will no longer be
duplicated. Added IPTABLES_AUTO_RULENUM and
IPCHAINS_AUTO_RULENUM so auto rules can be inserted at a
configurable point within iptables and ipchains policies.
- Psad now installs all perl modules within /usr/lib/psad.
- Removed /var/log/psad//scanlog file since it was wasting
too much disk.
- Made psad, psadwatchd, and diskmond take the machine hostname
from their respective config files. This makes installation
via the rpm easier, and is generally cleaner.
- Added scan destination in --Status output.
- Added --status-sort-dl (the default status output is now
sorted by ip address by default).
psad-1.2.1 (07/11/2003):
- Bugfix for multiple processes being spawned by psadwatchd
due to lack of proper config variables in the new split
daemon config files.
- Bugfix for old scan messages being regenerated if a HUP
signal is received.
- Bugfix for incorrectly calculating disk utilization in
diskmond.c.
- Extended install.pl to include compression for archived
files in /etc/psad.
- Added preserve questions in install.pl for the psad
signature and auto ips files.
- Bugfix for --USR1 command line switch not mapping to the
correct subroutine.
- Bugfix for psad man page missing the pipe character in
psadfifo line for syslog.conf.
psad-1.2 (06/18/2003):
- Added passive OS fingerprinting based on packet ttl, length,
tos, and id fields.
- Added dshield.org alerting capability.
- Added exec_external_script() for external script execution.
- Added auto blocked timeouts.
- Implemented config re-imports via HUP signals in a manner
similar to various other system daemons (sysylog, apache
etc.)
- Better --Status output that shows packet counts per protocol
for each ip.
- Added --ip-status for more verbose status output for a
particular ip address.
- Added config preservation code to install.pl.
- Added Psad::psyslog().
- Split psad.conf into a separate config file for each of the
four psad daemons.
- Completely re-worked the auto blocking code (made dedicated
files for iptables and ipchains block methods).
- Added danger level hash.
- Minor code cleanups (shorter hash keys, etc.).
psad-1.1.1 (04/26/2003):
- Bugfix for incorrect usage of %scan hash keys associated
with tcp/udp when the current protocol is icmp.
- Bugfix for being too strict on iptable default log string.
- Reworked USR1 signal handler so the Data::Dumper function
call is made in the main part of the psad code.
- Added a startup message for psad.
- Minor bugfix for leading whitespace in auto_ips.
psad-1.1 (04/20/2003):
- Added the IPTables::Parse module for better processing of
the iptables ruleset.
- Added --snort-sids so that iptables messages generated by
fwsnort can be included in alerts. Such alerts now include
the content fields of packets (fwsnort uses the iptables
string match module).
- Added the ability to specify entire networks in the auto
ips file through the use of the Net::IPv4Addr module.
- Better logging format that reinstates the current interval,
and adds an "overall stats" section that includes packet
counters per protocol.
- Removed the PROTO hash key since it was unnecesssary.
- Better benchmarking code.
- Bug fix for incorrectly looking for the "MAC" string in
iptables messages that could have been generated by the
FORWARD chain.
psad-1.0 (02/27/2003):
- Added --Benchmark and --packets command line options to support
psad benchmarking.
- Bugfix for improperly detecting NULL scans.
- Completely redesigned website.
psad-1.0.0-pre4 (11/26/2002):
- Rewrote kmsgsd and psadwatchd in C.
psad-7c4a910/ChangeLog.git 0000664 0000000 0000000 00000036656 12071203757 0015353 0 ustar 00root root 0000000 0000000 commit e7d4d477372e52bbf69fdd395b9d370ec131f6b8 (HEAD, refs/heads/master)
Author: Michael Rash
Date: Wed Jan 2 23:23:17 2013 -0500
added auto_min_dl5_blocking.conf file
test/conf/auto_min_dl5_blocking.conf | 596 ++++++++++++++++++++++++++++++++++
1 file changed, 596 insertions(+)
commit 0c59ffd1917d72ec81c8074eedfd8b9d624959e2
Author: Michael Rash
Date: Wed Jan 2 23:16:50 2013 -0500
changes since psad-2.2
ChangeLog.git | 368 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 368 insertions(+)
commit 98debf7924cfaae1541e7684f7ec3ac30e3eaaf7
Author: Michael Rash
Date: Wed Jan 2 23:12:43 2013 -0500
minor date update for psad-2.2.1 release
ChangeLog | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
commit da758cc9fffdc49bbf4ccf2236761e0f85da1f25
Author: Michael Rash
Date: Tue Jan 1 22:23:18 2013 -0500
bumped version to 2.2.1
VERSION | 2 +-
nf2csv | 2 +-
packaging/psad-nodeps.spec | 5 ++++-
packaging/psad-require-makemaker.spec | 5 ++++-
packaging/psad.spec | 5 ++++-
psad | 4 ++--
6 files changed, 16 insertions(+), 7 deletions(-)
commit 996ef41711b48643029c31c7d5c7e7cd9a9d035b
Author: Michael Rash
Date: Tue Jan 1 22:20:00 2013 -0500
Added EMAIL_THROTTLE for email throttling
Added the ability to throttle emails generated by psad via a new
EMAIL_THROTTLE variable which is implemented as a per-IP threshold. That
is, if EMAIL_THROTTLE is set to "10", then psad will only send 1/10th as
many emails for each scanning IP as it would have normally. This feature
was suggested by Naji Mouawad.
CREDITS | 4 ++++
ChangeLog | 10 +++++++++-
psad | 10 +++++++++-
psad.conf | 8 ++++++++
test/conf/auto_blocking.conf | 8 ++++++++
test/conf/default_psad.conf | 8 ++++++++
test/conf/disable_ipv6_detection.conf | 8 ++++++++
test/conf/enable_ack_detection.conf | 8 ++++++++
test/conf/ignore_tcp.conf | 8 ++++++++
test/conf/ignore_udp.conf | 8 ++++++++
test/conf/require_DROP_syslog_prefix_str.conf | 8 ++++++++
test/conf/require_missing_syslog_prefix_str.conf | 8 ++++++++
12 files changed, 94 insertions(+), 2 deletions(-)
commit b39dc01133d7b0e981c58622b5f0a9c48c979b81
Author: Michael Rash
Date: Tue Jan 1 20:56:00 2013 -0500
Configurable auto-blocking timeout values.
Oscar Marley suggested configurable auto-blocking timeout values depending on
the danger level that a scan or attack achieves. This resulted in the
implementation of the AUTO_BLOCK_DL*_TIMEOUT variables.
CREDITS | 5 ++
psad | 73 +++++++++++++++-------
psad.conf | 9 +++
test/conf/auto_blocking.conf | 11 +++-
test/conf/default_psad.conf | 9 +++
test/conf/disable_ipv6_detection.conf | 9 +++
test/conf/enable_ack_detection.conf | 9 +++
test/conf/ignore_tcp.conf | 9 +++
test/conf/ignore_udp.conf | 9 +++
test/conf/require_DROP_syslog_prefix_str.conf | 9 +++
test/conf/require_missing_syslog_prefix_str.conf | 9 +++
test/test-psad.pl | 26 +++++++-
12 files changed, 162 insertions(+), 25 deletions(-)
commit d78f288f0577e59e1b36447604ea040dc302caea
Author: Michael Rash
Date: Sat Dec 22 22:19:19 2012 -0500
added --analysis-auto-block mode to allow auto-responses to be testing in -A mode
psad | 36 +++++++++++++++++++++++-------------
psad.8 | 8 +++++++-
2 files changed, 30 insertions(+), 14 deletions(-)
commit 1d2602e6ba83f27042c6e59fa39d2320e0477ef3
Author: Michael Rash
Date: Sat Dec 22 22:15:14 2012 -0500
Added --enable-auto-block-tests for testing the auto-blocking functionality in psad
test/conf/auto_blocking.conf | 579 ++++++++++++++++++++++++++++++++++++++++++
test/test-psad.pl | 72 ++++--
2 files changed, 633 insertions(+), 18 deletions(-)
commit 574d31aff2702412d78016d509beedf8e866b7db (refs/remotes/web/master, refs/remotes/origin/master)
Author: Michael Rash
Date: Thu Dec 20 21:06:46 2012 -0500
Detect Topera IPv6 scans when IP options are logged
Added detection for Topera IPv6 scans when --log-ip-options is used in
the ip6tables logging rule. When this option is not used, the previous psad-2.2 release detected Topera scans. An example TCP SYN packet
generated by Topera when --log-ip-options is used looks like this (note the series of empty IP options strings "OPT ( )":
Dec 20 20:10:40 rohan kernel: [ 488.495776] DROP IN=eth0 OUT= MAC=00:1b:b9:76:9c:e4:00:13:46:3a:41:36:86:dd
SRC=2012:1234:1234:0000:0000:0000:0000:0001 DST=2012:1234:1234:0000:0000:0000:0000:0002 LEN=132 TC=0 HOPLIMIT=64
FLOWLBL=0 OPT ( ) OPT ( ) OPT ( ) OPT ( ) OPT ( ) OPT ( ) OPT ( ) OPT ( ) OPT ( ) PROTO=TCP SPT=61287 DPT=1 WINDOW=8192 RES=0x00 SYN
URGP=0
ChangeLog | 14 +
psad | 62 +-
.../scans/iptables/topera_ipv6_syn_scan_no_ip_opts | 1058 ++++++++++++++++++++
.../iptables/topera_ipv6_syn_scan_with_ip_opts | 1046 +++++++++++++++++++
test/test-psad.pl | 36 +
5 files changed, 2200 insertions(+), 16 deletions(-)
commit bd89cfbad0cdc4540f1b983811e40803b8fa29b9
Author: Michael Rash
Date: Mon Dec 17 23:05:56 2012 -0500
Parse fwsnort rules for 'msg' fields
Added the ability to acquire Snort rule 'msg' fields from fwsnort if
it's also installed. A new variable FWSNORT_RULES_DIR tells psad where
to look for the fwsnort rule set. This fixes a problem reported by Pui
Edylie to the psad mailing list where fwsnort logged an attack that psad
could not map back to a descriptive 'msg' field.
CREDITS | 6 ++
ChangeLog | 6 ++
psad | 106 ++++++++++++----------
psad.conf | 1 +
test/conf/default_psad.conf | 1 +
test/conf/disable_ipv6_detection.conf | 1 +
test/conf/enable_ack_detection.conf | 1 +
test/conf/ignore_tcp.conf | 1 +
test/conf/ignore_udp.conf | 1 +
test/conf/require_DROP_syslog_prefix_str.conf | 1 +
test/conf/require_missing_syslog_prefix_str.conf | 1 +
11 files changed, 77 insertions(+), 49 deletions(-)
commit 361281e7d38c68b8e8c201ca31ea9be0bc7ec858
Author: Michael Rash
Date: Sat Dec 15 22:12:22 2012 -0500
added nmap scan style details to syslog output
psad | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
commit 9659621061cd1a8032e736294cedcb3d79b7ae72
Author: Michael Rash
Date: Sat Dec 15 22:06:31 2012 -0500
completed IP protocol scan detection task
todo.org | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
commit 19bee218741a725a8085a937046164fea47ec310
Author: Michael Rash
Date: Sat Dec 15 22:03:26 2012 -0500
added IP protocol scan output to psad emails
psad | 69 +++++++++++++++++++++++++++++++++---------------------------------
1 file changed, 35 insertions(+), 34 deletions(-)
commit 6383941e87c5cadbc6f34eed99adcf26e2264818
Author: Michael Rash
Date: Sat Dec 15 22:02:42 2012 -0500
additional regex's to look for perl warnings
test/test-psad.pl | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
commit 8018338cd7668da7447fc5e106f4ae2285a972bf
Author: Michael Rash
Date: Fri Dec 14 21:04:31 2012 -0500
[test suite] added --analysis-write-data to psad test command line
test/test-psad.pl | 34 +++++++++++++++++-----------------
1 file changed, 17 insertions(+), 17 deletions(-)
commit 668453375e2256c6a7e182b211ac2acce0cb4764
Author: Michael Rash
Date: Sun Dec 9 21:31:22 2012 -0500
added 'Other' protocols to per-IP 'Global stats' output for protocol scans
psad | 35 +++++++++++++++++++++++++++++------
1 file changed, 29 insertions(+), 6 deletions(-)
commit 1e9afc6f82328f16ca415524484b0fc3b354fe9e
Author: Michael Rash
Date: Sun Dec 9 21:22:50 2012 -0500
remove 'multiproto' hash key in favor of new 'tot_protocols' hash key (used in -sO protocol scan detection)
psad | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
commit 760e02b3c2c796e4856ec1338684c84679a15580
Author: Michael Rash
Date: Sun Dec 9 21:14:46 2012 -0500
minor bug fix for uninitialized variable usage in ICMP6 invalid type/code detection
psad | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
commit 4e059858de6bf4d553591c83fe022c17b3904732
Author: Michael Rash
Date: Fri Dec 7 22:34:08 2012 -0500
added IP protocol scan test
test/test-psad.pl | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
commit 9fd7ce6cdb2303b1d698decb9708980e4e1997ee
Author: Michael Rash
Date: Fri Dec 7 22:32:46 2012 -0500
removed ununsed is_digit() function
psad | 6 ------
1 file changed, 6 deletions(-)
commit 91dfe52f4a340ba52d70e03b40fb43b71774b0d5
Author: Michael Rash
Date: Fri Dec 7 21:23:22 2012 -0500
first cut at IP protocol scan detection (nmap -sO)
ChangeLog | 11 +-
VERSION | 2 +-
nf2csv | 2 +-
psad | 213 +++++++--
psad.conf | 6 +
test/conf/default_psad.conf | 6 +
test/conf/disable_ipv6_detection.conf | 6 +
test/conf/enable_ack_detection.conf | 6 +
test/conf/ignore_tcp.conf | 6 +
test/conf/ignore_udp.conf | 6 +
test/conf/require_DROP_syslog_prefix_str.conf | 6 +
test/conf/require_missing_syslog_prefix_str.conf | 6 +
test/scans/iptables/proto_scan | 510 ++++++++++++++++++++++
13 files changed, 745 insertions(+), 41 deletions(-)
commit 518880f270688cd903112395db97db85a89212ed
Author: Michael Rash
Date: Fri Dec 7 21:18:58 2012 -0500
added 'protocols' file in support of IP protocol scan detection (nmap -sO)
install.pl | 6 +++---
protocols | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 67 insertions(+), 3 deletions(-)
commit f20a57a6a37963ea1b27931d297f0791fbca544f
Author: Michael Rash
Date: Sat Dec 1 14:36:08 2012 -0500
replaced TODO with todo.org org mode file
TODO | 91 --------------------------------------------------------------
todo.org | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 85 insertions(+), 91 deletions(-)
commit eab733f4f51270116daba9eae8d221e236af9c26
Author: Michael Rash
Date: Thu Nov 22 22:17:00 2012 -0500
another hyphen fix
psad.8 | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
commit f2c44bbd02f8db51758a3160c527245ba8879599
Author: Michael Rash
Date: Thu Nov 22 22:16:00 2012 -0500
applied hyphen fix from Franck Joncourt
psad.8 | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
commit a3d8daabbc60da23116141fd5d899573c3bda199
Author: Michael Rash
Date: Tue Nov 20 21:00:00 2012 -0500
added Gregorio Narvaez
CREDITS | 4 ++++
1 file changed, 4 insertions(+)
commit ff46fe12b238b7f7b63b2f31345bb6a8f99f7efe
Author: Michael Rash
Date: Tue Nov 20 20:58:00 2012 -0500
Bug fix for NetAddr::IP usage in --analysis-fields IP search mode
Bug fix in --Analyze mode when IP fields are to be searched with the
--analysis-fields argument (such as --analysis-fields "SRC:1.2.3.4").
The bug was reported by Gregorio Narvaez, and looked like this:
Use of uninitialized value $_[0] in length at
../../blib/lib/NetAddr/IP/UtilPP.pm (autosplit into
../../blib/lib/auto/NetAddr/IP/UtilPP/hasbits.al) line 126.
Use of uninitialized value $_[0] in length at
../../blib/lib/NetAddr/IP/UtilPP.pm (autosplit into
../../blib/lib/auto/NetAddr/IP/UtilPP/hasbits.al) line 126.
Bad argument length for NetAddr::IP::UtilPP::hasbits, is 0, should be
128 at ../../blib/lib/NetAddr/IP/UtilPP.pm (autosplit into
../../blib/lib/auto/NetAddr/IP/UtilPP/_deadlen.al) line 122.
Added --stdin argument to allow psad to collect iptables log data from
STDIN in --Analyze mode.
ChangeLog | 18 +++++
psad | 59 +++++++++++----
psad.8 | 6 ++
test/install.answers | 24 ++++++
test/test-psad.pl | 197 +++++++++++++++++++++++++++++++++++++++++++++++++-
5 files changed, 289 insertions(+), 15 deletions(-)
commit 30120fbc5d44519aa378333c494e456e6aded331 (tag: refs/tags/psad-2.3-pre1)
Author: Michael Rash
Date: Mon Jun 11 20:58:36 2012 -0400
bumped version to psad-2.3-pre1
VERSION | 2 +-
nf2csv | 2 +-
psad | 4 ++--
3 files changed, 4 insertions(+), 4 deletions(-)
commit 99ac4ab1eed310adbe4d24bdee9b67ee6dfb7905
Author: Michael Rash
Date: Mon Jun 11 20:56:19 2012 -0400
minor comment wording update w.r.t. SYSLOG_DAEMON usage
psad.conf | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
commit e5ada77ddf8dbec564fee5e50734460e28b5a185
Author: Michael Rash
Date: Mon Jun 11 20:55:50 2012 -0400
INSTALL_ROOT resolution bug fix (found by Kat)
CREDITS | 4 ++++
kmsgsd.c | 20 ++++++++++++++++++++
2 files changed, 24 insertions(+)
commit 8dedbcad794e3b539f2df202feb8a15b50e6e75a
Author: Michael Rash
Date: Sat May 26 21:30:50 2012 -0400
removed legacy psadwatchd.conf file references
packaging/psad-nodeps.spec | 4 +---
packaging/psad-require-makemaker.spec | 4 +---
packaging/psad.spec | 4 +---
3 files changed, 3 insertions(+), 9 deletions(-)
psad-7c4a910/FW_EXAMPLE_RULES 0000664 0000000 0000000 00000003227 12071203757 0015367 0 ustar 00root root 0000000 0000000
The following firewall rulesets are examples of rulesets that are compatible
with psad. Basically, the only criteria is have the firewall log and
drop packets that should not be allowed through. Then a port scan will
manifest itself within /var/log/messages as packets are dropped and logged,
at which time these messages will be written to the /var/lib/psad/psadfifo
named pipe and analyzed by psad.
### iptables:
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
ACCEPT tcp -- 129.xx.xx.xx 64.44.21.15 tcp dpt:22 flags:SYN,RST,ACK/SYN
ACCEPT tcp -- 208.xx.xx.xx 64.44.21.15 tcp dpt:22 flags:SYN,RST,ACK/SYN
ACCEPT tcp -- 24.xx.xx.xx 64.44.21.15 tcp dpt:22 flags:SYN,RST,ACK/SYN
ACCEPT tcp -- 208.xx.xx.xx 64.44.21.15 tcp dpt:22 flags:SYN,RST,ACK/SYN
ACCEPT tcp -- 0.0.0.0/0 64.44.21.15 tcp dpt:25 flags:SYN,RST,ACK/SYN
ACCEPT tcp -- 0.0.0.0/0 64.44.21.15 tcp dpt:80 flags:SYN,RST,ACK/SYN
LOG all -- 0.0.0.0/0 0.0.0.0/0 LOG level warning prefix `DROP '
DROP all -- 0.0.0.0/0 0.0.0.0/0
Chain FORWARD (policy ACCEPT)
target prot opt source destination
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
LOG all -- 0.0.0.0/0 0.0.0.0/0 LOG level warning prefix `DROP '
DROP all -- 0.0.0.0/0 0.0.0.0/0
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
psad-7c4a910/FW_HELP 0000664 0000000 0000000 00000002665 12071203757 0014057 0 ustar 00root root 0000000 0000000 The main requirement for an iptables configuration to be compatible with psad
is simply that iptables logs packets. This is commonly accomplished by adding
rules to the INPUT and FORWARD chains like so:
iptables -A INPUT -j LOG
iptables -A FORWARD -j LOG
The rules above should be added at the end of the INPUT and FORWARD chains
after all ACCEPT rules for legitimate traffic and just before a corresponding
DROP rule for traffic that is not to be allowed through the policy. Note that
iptables policies can be quite complex with protocol, network, port, and
interface restrictions, user defined chains, connection tracking rules, and
much more. There are many pieces of software such as Shorewall and Firewall
Builder, that build iptables policies and take advantage of the advanced
filtering and logging capabilities offered by iptables. Generally the policies
built by such pieces of software are compatible with psad since they
specifically add rules that instruct iptables to log packets that are not part
of legitimate traffic. Psad can be configured to only analyze those iptables
messages that contain specific log prefixes (which are added via the
--log-prefix option), but the default as of version 1.3.2 is for psad to
analyze all iptables log messages for port scans, probes for backdoor
programs, and other suspect traffic. See the list of features offered by psad
for more information (http://www.cipherdyne.org/psad/features.html).
psad-7c4a910/INSTALL 0000664 0000000 0000000 00000006460 12071203757 0014036 0 ustar 00root root 0000000 0000000 Installation notes:
QUICK AND EASY INSTALLATION INSTRUCTIONS:
Just run the psad installation script "install.pl" from the psad
sources directory:
# ./install.pl
This will result in a functional installation of psad on your system. It is
safe to run the install.pl script even if you already have psad installed on
your system. The configuration can (optionally) be preserved from the
previous installation (you will be prompted for this if an existing psad
installation is detected). For more information, read on:
==============================================================================
IMPORTANT:
psad makes use of log messages that are generated by iptables as it logs
(and drops) packets. Hence if your firewall is not configured to log packets,
then psad will NOT detect port scans or anything else. Usually the best and
most secure way to configure your firewall is to first put the minimal rules
needed to allow only necessary traffic to and from your machine, and then have
default LOG and DROP rules toward the end of the firewall ruleset. Some
example firewall rulesets that are compatible with psad are contained within
the file FW_EXAMPLE_RULES, and the "iptables.sh" script available at the
following link contains a script to build a compatible iptables policy:
http://www.cipherdyne.org/LinuxFirewalls/ch01/iptables.sh.tar.gz
Note that psad is only compatible (as of version 2.1.3) with iptables
firewalls, but support for other firewall logging formats (such as logs
generated by ipfw and pf) is coming soon.
DEPENDENCIES:
psad requires several perl modules that may or may not already be
installed on your Linux system. These modules are included in the deps/
directory in the psad sources, and the list of modules is:
Bit::Vector
Date::Calc
IPTables::ChainMgr
IPTables::Parse
NetAddr::IP
Storable
Unix::Syslog
psad also includes a whois client written by Marco d'Itri (see the deps/whois
directory). This client does better than others at collecting the correct
whois information for a given IP address.
CONNECTION TRACKING:
As of kernel version 2.4.13, there is a bug in the connection tracking
code that can drop packets that are part of legitimate TCP connections that
have entered into the CLOSE_WAIT state depending on how late they arrive.
Since these packets are drop whenever the iptables policy is configured in
a default drop stance, psad interprets them as potentially belonging to a
scan. The source of the problem is an inappropriately low timeout value, and
fortunately this problem is mostly fixed (or at least minimized) by the
trivial kernel patch "conntrack_patch" included with the psad source code.
If you start noticing lots of ACK/FIN, ACK, and even RST packets being denied
by iptables from legtimate sessions, then you may want to apply this patch.
This will of course require the kernel to be recompiled. For more information
on how to do this, see the Kernel-HOWTO available at:
http://www.digitalhermit.com/linux/Kernel-Build-HOWTO.html
UPGRADES:
You can install a new version of psad over an existing one; just run
install.pl. The installation script will preserve any old configuration
parameters when installing the new versions of psad, psadwatchd, and kmsgsd.
UN-INSTALLING:
psad can be completely removed from the system by executing
install.pl with the --uninstall option.
psad-7c4a910/LICENSE 0000664 0000000 0000000 00000043077 12071203757 0014017 0 ustar 00root root 0000000 0000000 GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
Copyright (C) 19yy
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.
psad-7c4a910/Makefile 0000664 0000000 0000000 00000003063 12071203757 0014441 0 ustar 00root root 0000000 0000000 #
##########################################################################
#
# Author: Michael Rash (mbr@cipherdyne.org)
#
# Credits: (see the CREDITS file)
#
# Version: 1.4.1
#
# Copyright (C) 1999-2002 Michael Rash (mbr@cipherdyne.org)
#
# License (GNU Public License):
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
# USA
#
##########################################################################
#
### default
all : kmsgsd.c psadwatchd.c psad_funcs.c strlcpy.c strlcat.c psad.h
/usr/bin/gcc -Wall -O kmsgsd.c psad_funcs.c strlcpy.c strlcat.c -o kmsgsd
/usr/bin/gcc -Wall -O psadwatchd.c psad_funcs.c strlcpy.c strlcat.c -o psadwatchd
### debug mode
debug : kmsgsd.c psadwatchd.c psad_funcs.c strlcpy.c strlcat.c psad.h
/usr/bin/gcc -Wall -g -DDEBUG kmsgsd.c psad_funcs.c strlcpy.c strlcat.c -o kmsgsd
/usr/bin/gcc -Wall -g -DDEBUG psadwatchd.c psad_funcs.c strlcpy.c strlcat.c -o psadwatchd
#install : kmsgsd
# if [ -x kmsgsd ]; then \
# /bin/cp kmsgsd /usr/sbin/kmsgsd
clean :
if [ -f a.out ]; then rm a.out; fi
if [ -f core ]; then rm core; fi
if [ -f kmsgsd ]; then rm kmsgsd; fi
if [ -f psadwatchd ]; then rm psadwatchd; fi
psad-7c4a910/README 0000664 0000000 0000000 00000012302 12071203757 0013655 0 ustar 00root root 0000000 0000000 psad (Port Scan Attack Detector)
Version: 3.0
Author: Michael Rash (mbr@cipherdyne.org)
Website: http://www.cipherdyne.org/
Thanks to: (see the CREDITS file).
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
DESCRIPTION:
The Port Scan Attack Detector (psad) is a collection of two lightweight
system daemons written in Perl and in C that are designed to work with Linux
iptables firewalling code to detect port scans and other suspect traffic. It
features a set of highly configurable danger thresholds (with sensible
defaults provided), verbose alert messages that include the source,
destination, scanned port range, begin and end times, tcp flags and
corresponding nmap options, reverse DNS info, email and syslog alerting,
automatic blocking of offending ip addresses via dynamic configuration of
iptables rulesets, passive operating system fingerprinting, and DSheild
reporting. In addition, psad incorporates many of the tcp, udp, and icmp
signatures included in the snort intrusion detection system
(http://www.snort.org) to detect highly suspect scans for various backdoor
programs (e.g. EvilFTP, GirlFriend, SubSeven), DDoS tools (mstream, shaft),
and advanced port scans (syn, fin, xmas) which are easily leveraged against a
machine via nmap. psad can also alert on snort signatures that are logged
via fwsnort, which makes use of the iptables string match module to detect
application layer signatures.
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
CONFIGURATION INFORMATION:
Information on config keywords referenced by psad may be found both in the
psad(8) man page, and also here:
http://www.cipherdyne.org/psad/docs/config.html
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
METHODOLOGY:
All information psad analyzes is gathered from iptables log messages.
psad by default reads the /var/log/messages file for new iptables messages and
optionally writes them out to a dedicated file (/var/log/psad/fwdata).
psad is then responsible for applying the danger threshold and signature logic
in order to determine whether or not a port scan has taken place, send
appropriate alert emails, and (optionally) block offending ip addresses. psad
includes a signal handler such that if a USR1 signal is received, psad will
dump the contents of the current scan hash data structure to
/var/log/psad/scan_hash.$$ where "$$" represents the pid of the running psad
daemon.
NOTE: Since psad relies on iptables to generate appropriate log messages
for unauthorized packets, psad is only as good as the logging rules included
in the iptables ruleset. Usually the best way setup the firewall is with
default "drop and log" rules at the end of the ruleset, and include rules
above this last rule that only allow traffic that should be allowed through.
Upon execution, the psad daemon will attempt to ascertain whether or not such
a default deny rule exists, and will warn the administrator if it doesn't.
See the FW_EXAMPLE_RULES file for example firewall rulesets that are
compatible with psad.
Additionally, extensive coverage of psad is included in the book "Linux
Firewalls: Attack Detection and Response" published by No Starch Press, and a
supporting script in this book is compatible with psad. This script can be
found here:
http://www.cipherdyne.org/LinuxFirewalls/ch01/
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
INSTALLATION:
See the INSTALL file in the psad sources directory.
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
FIREWALL SETUP:
See the FW_HELP file in the psad sources directory. Also, read the
README.SYSLOG file.
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
PLATFORMS:
psad has been tested on RedHat 6.2 - 9.0, Fedora Core 1 and 2, and
Gentoo Linux systems running various kernels. The only program that
specifically depends on the RedHat architecture is psad-init, which depends
on /etc/rc.d/init.d/functions. For non-RedHat systems a more generic init
script is included called "psad-init.generic". The psad init scripts are
mostly included as a nicety; psad can be run from the command line like any
other program.
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
COPYRIGHT:
Copyright (C) 1999-2012 Michael Rash (mbr@cipherdyne.org)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
psad makes use of many of the tcp, udp, and icmp signatures available in
Snort (written by Marty Roesch, see http://www.snort.org). Snort is a
registered trademark of Sourcefire, Inc.
psad-7c4a910/README.RPM 0000664 0000000 0000000 00000005644 12071203757 0014325 0 ustar 00root root 0000000 0000000
Building RPM files that are compatible with all possible Linux distributions
is a difficult task. If a given RPM file that is downloaded from
http://www.cipherdyne.org/ is not compatible with your particular Linux
distro, then you can use the "cd_rpmbuilder" ("CipherDyne RPM Builder") to
build an RPM file for you on your own system.
The command line interface to cd_rpmbuilder is simple, and one command line
argument is always required "-p " so that cd_rpmbuilder knows which
CipherDyne software project you want to build:
# cd_rpmbuilder -p
Note that cd_rpmbuilder is normally as root because it builds RPM's within
the /usr/src/redhat/ directory by default. However, if you would like to
build as a normal user within a directory of your choosing you can do:
# cd_rpmbuilder -p -r
By default, cd_rpmbuilder builds the latest version of the specified project,
but if you want to build an older version, use the -b flag:
# cd_rpmbuilder -p -b
If you want to see verbose output (including all output of the system
rpmbuild command), then use the -v flag:
# cd_rpmbuilder -p -v
Finally, here is some sample output for building the psad project available
at http://www.cipherdyne.org/psad/:
# ./cd_rpmbuilder -p psad
[+] Getting latest version file:
http://www.cipherdyne.org/psad/psad-latest
[+] Downloading file:
http://www.cipherdyne.org/psad/download/psad-2.0.1.spec
[+] Downloading file:
http://www.cipherdyne.org/psad/download/psad-2.0.1.spec.md5
[+] Valid md5 sum check for psad-2.0.1.spec
[+] Downloading file:
http://www.cipherdyne.org/psad/download/psad-2.0.1.tar.gz
[+] Downloading file:
http://www.cipherdyne.org/psad/download/psad-2.0.1.tar.gz.md5
[+] Valid md5 sum check for psad-2.0.1.tar.gz
[+] Building RPM, this may take a little while...
[+] The following RPMS were successfully built:
/usr/src/redhat/SRPMS/psad-2.0.1-1.src.rpm (source RPM)
/usr/src/redhat/RPMS/i386/psad-2.0.1-1.i386.rpm
You can view the usage information like so:
[mbr@minastirith ~/src/psad]$ ./cd_rpmbuilder -h
cd_rpmbuilder; the CipherDyne RPM builder
[+] Version: 0.9
[+] By Michael Rash (mbr@cipherdyne.org, http://www.cipherdyne.org)
Usage: cd_rpmbuilder -p [-b ] [-r ] [-v] [-V] [-h]
Options:
-p, --project - This can be one of "psad", "fwknop",
"gpgdir", or "fwsnort".
-b, --build-version - Build a specific project version.
-r, --rpm-build-dir - Change the RPM build directory from the
default of /usr/src/redhat.
-v, --verbose - Run in verbose mode.
-V, --Version - Print version and exit.
-h, --help - Display usage information.
psad-7c4a910/README.SYSLOG 0000664 0000000 0000000 00000005163 12071203757 0014703 0 ustar 00root root 0000000 0000000
This information is documented in the psad.conf file as well:
By default, psad acquires iptables log data from the /var/log/messages
file which the local syslog daemon (usually) writes iptables log messages
to. If the ENABLE_SYSLOG_FILE variable is set to "N", then psad
reconfigures syslog to write iptables log data to the
/var/lib/psad/psadfifo fifo file where the messages are picked up by kmsgsd
written to the file /var/log/psad/fwdata for analysis by psad. On some
systems, having syslog communicate log data to kmsgsd can be problematic
(syslog configs and external factors such as Apparmor and SELinux can play
a role here), so leaving the ENABLE_SYSLOG_FILE variable set to "Y" is
usually recommended.
*** Pre psad-2.1.3 information below ***
TESTING YOUR INSTALLATION:
The psad installer does its best to reconfigure your syslog daemon to write
all kern.info messages (or higher) to the /var/lib/psad/psadfifo named pipe
for analysis. However, in order to test whether your installation is working
or not, you can do the following as root:
$ iptables -I INPUT -i lo -p tcp --dport 3003 -j LOG --log-prefix "Inbound "
$ telnet localhost 3003
Assuming that psad is running, this should generate in /var/log/psad/fwdata
something similar to:
Jun 15 23:37:33 kernel: Inbound IN=lo OUT=
MAC= SRC=127.0.0.1 DST=127.0.0.1 LEN=60 TOS=0x10 PREC=0x00
TTL=64 ID=47312 DF PROTO=TCP SPT=40945 DPT=3003 WINDOW=32767 RES=0x00 SYN
URGP=0
Also, executing "psad --Status" should display (among other things) something
like:
Iptables prefix counters:
"Inbound": 1
If the /var/log/psad/fwdata file is empty but you are getting messages in the
system log (for example when you type "dmesg" or in /var/log/messages), then
you should make sure that psad has the fifo open:
$ lsof | grep psadfifo
You should get something along the lines of:
syslogd 942 root 20u FIFO 3,5 544097 /var/lib/psad/psadfifo
kmsgsd 25457 root 0u FIFO 3,5 544097 /var/lib/psad/psadfifo
The main requirement is that iptables logs are getting logged via kern.info
(or at a higher priority such as "warn") by syslog. The default for the
iptables LOG target is log iptables messages at the "warn" priority, but
this can be changed with the --log-level option. For example, to have
iptables generate logs at the "info" priority in the INPUT chain, the
following command could be used:
# iptables -A INPUT -j LOG --log-level info
This may help cut down on iptables logs being sent to the console if your
syslog.conf instructs syslog to log kernel messages at a "warn" level or
higher to the console device.
psad-7c4a910/SCAN_LOG 0000664 0000000 0000000 00000003443 12071203757 0014153 0 ustar 00root root 0000000 0000000
This file contains a sample psad alert, and many more examples can be found
here:
http://www.cipherdyne.org/psad/docs/
Here is an example of psad alert (version 2.0.2) for a scan for the
Microsoft VNC service against my Linux box (running kernel 2.6.18):
=-=-=-=-=-=-=-=-=-=-=-= Fri Dec 22 12:10:38 2006 =-=-=-=-=-=-=-=-=-=-=-=
Danger level: [2] (out of 5)
Scanned tcp ports: [5900: 1 packets]
tcp flags: [SYN: 1 packets, Nmap: -sT or -sS]
iptables chain: INPUT (prefix "DROP"), 1 packets
Source: 71.127.83.44
DNS: static-71-127-83-44.aubnin.fios.verizon.net
Destination: 71.127.x.x
Syslog hostname: minastirith
Current interval: Fri Dec 22 12:10:33 2006 (start)
Fri Dec 22 12:10:38 2006 (end)
Overall scan start: Thu Dec 21 20:37:49 2006
Total email alerts: 36
Complete tcp range: [1433-5900]
chain: interface: tcp: udp: icmp:
INPUT eth0 44 0 0
[+] tcp scan signatures:
"MISC VNC communication attempt"
dst port: 5900 (no server bound to local port)
flags: SYN
psad_id: 100202
chain: INPUT
packets: 1
classtype: attempted-admin
reference: (url) http://isc.sans.org/port_details.php?port=5900
reference: (url) http://secunia.com/advisories/20107
[+] Whois Information:
Verizon Internet Services Inc. VIS-71-96 (NET-71-96-0-0-1)
71.96.0.0 - 71.127.255.255
PORTAL MAGIC FTTP (NET-71-127-83-40-1)
71.127.83.40 - 71.127.83.47
# ARIN WHOIS database, last updated 2006-12-21 19:10
# Enter ? for additional hints on searching ARIN's WHOIS database.
=-=-=-=-=-=-=-=-=-=-=-= Fri Dec 22 12:10:38 2006 =-=-=-=-=-=-=-=-=-=-=-=
psad-7c4a910/VERSION 0000664 0000000 0000000 00000000006 12071203757 0014043 0 ustar 00root root 0000000 0000000 2.2.1
psad-7c4a910/auto_dl 0000664 0000000 0000000 00000002154 12071203757 0014353 0 ustar 00root root 0000000 0000000 #
#############################################################################
#
# This file is used by psad to elevate/decrease the danger levels of IP
# addresses (or networks in CIDR notation) so that psad does not have to
# apply the normal signature logic. This is useful if certain IP addresses
# or networks are known trouble makers and should automatically be assigned
# higher danger levels than would normally be assigned. Also, psad can be
# made to ignore certain IP addresses or networks if a danger level of "0" is
# specified. Optionally, danger levels for IPs/networks can be influenced
# based on protocol (tcp, udp, icmp).
#
#############################################################################
#
# /;
#
# Examples:
#
# 10.111.21.23 5; # Very bad IP.
# 127.0.0.1 0; # Ignore this IP.
# 10.10.1.0/24 0; # Ignore traffic from this entire class C.
# 192.168.10.4 3 tcp; # Assign danger level 3 if protocol is tcp.
# 10.10.1.0/24 3 tcp/1-1024; # Danger level 3 for tcp port range
psad-7c4a910/bump_version.pl 0000775 0000000 0000000 00000002560 12071203757 0016052 0 ustar 00root root 0000000 0000000 #!/usr/bin/perl -w
#
#############################################################################
#
# File: bump_version.pl
#
# Purpose: Minor script to enforce consistency in psad version tags.
#
#############################################################################
#
use strict;
my @files = qw(
psad
nf2csv
);
my $new_version = $ARGV[0] or die "[*] $0 ";
open F, '< VERSION' or die "[*] Could not open VERSION file: $!";
my $old_version = ;
close F;
chomp $old_version;
print "[+] Updating software versions...\n";
for my $file (@files) {
if ($file =~ /\.c/) {
###* Version: 1.8.4-pre2
my $search_re = qr/^\*\s+Version:\s+$old_version/;
my $replace_str = '* Version: ' . $new_version;
system qq{perl -p -i -e 's|$search_re|} .
qq{$replace_str|' $file};
} else {
### Version: 1.8.4
my $search_re = qr/#\s+Version:\s+$old_version/;
my $replace_str = '# Version: ' . $new_version;
system qq{perl -p -i -e 's|$search_re|$replace_str|' $file};
### my $version = '1.8.4';
$search_re = qr/^my\s+\x24version\s+=\s+'$old_version';/;
$replace_str = q|my \x24version = '| . $new_version . q|';|;
system qq{perl -p -i -e "s|$search_re|$replace_str|" $file};
}
}
system qq{perl -p -i -e 's|$old_version|$new_version|' VERSION};
exit 0;
psad-7c4a910/chainmgr_test.pl 0000775 0000000 0000000 00000006035 12071203757 0016172 0 ustar 00root root 0000000 0000000 #!/usr/bin/perl -w
use strict;
### path to default psad library directory for psad perl modules
my $psad_lib_dir = '/usr/lib/psad';
### import psad perl modules
&import_psad_perl_modules();
my $ipt = new IPTables::ChainMgr(
'iptables' => '/sbin/iptables',
'verbose' => 1
);
my $total_rules = 0;
my ($rv, $out_ar, $err_ar) = $ipt->create_chain('filter', 'PSAD');
print "create_chain() rv: $rv\n";
print "$_\n" for @$out_ar;
print "$_\n" for @$err_ar;
($rv, $out_ar, $err_ar) = $ipt->add_jump_rule('filter', 'INPUT', 'PSAD');
print "add_jump_rule() rv: $rv\n";
print "$_\n" for @$out_ar;
print "$_\n" for @$err_ar;
($rv, $out_ar, $err_ar) = $ipt->add_ip_rule('1.1.1.1',
'0.0.0.0/0', 10, 'filter', 'PSAD', 'DROP');
print "add_ip_rule() rv: $rv\n";
print "$_\n" for @$out_ar;
print "$_\n" for @$err_ar;
($rv, $total_rules) = $ipt->find_ip_rule('1.1.1.1', '0.0.0.0/0', 'filter', 'PSAD', 'DROP');
print "find ip: $rv, total chain rules: $total_rules\n";
($rv, $out_ar, $err_ar) = $ipt->add_ip_rule('2.2.1.1', '0.0.0.0/0', 10,
'filter', 'PSAD', 'DROP');
print "add_ip_rule() rv: $rv\n";
print "$_\n" for @$out_ar;
print "$_\n" for @$err_ar;
($rv, $out_ar, $err_ar) = $ipt->add_ip_rule('2.2.4.1', '0.0.0.0/0', 10,
'filter', 'PSAD', 'DROP');
print "add_ip_rule() rv: $rv\n";
print "$_\n" for @$out_ar;
print "$_\n" for @$err_ar;
($rv, $out_ar, $err_ar) = $ipt->delete_ip_rule('1.1.1.1', '0.0.0.0/0',
'filter', 'PSAD', 'DROP');
print "delete_ip_rule() rv: $rv\n";
print "$_\n" for @$out_ar;
print "$_\n" for @$err_ar;
($rv, $out_ar, $err_ar) = $ipt->delete_chain('filter', 'INPUT', 'PSAD');
print "delete_chain() rv: $rv\n";
print "$_\n" for @$out_ar;
print "$_\n" for @$err_ar;
($rv, $out_ar, $err_ar) = $ipt->run_ipt_cmd('/sbin/iptables -nL INPUT');
print "list on 'INPUT' chain rv: $rv\n";
print for @$out_ar;
print for @$err_ar;
($rv, $out_ar, $err_ar) = $ipt->run_ipt_cmd('/sbin/iptables -nL INPU');
print "bogus list on 'INPU' chain rv: $rv (this is expected).\n";
print for @$out_ar;
print for @$err_ar;
exit 0;
sub import_psad_perl_modules() {
my $mod_paths_ar = &get_psad_mod_paths();
push @$mod_paths_ar, @INC;
splice @INC, 0, $#$mod_paths_ar+1, @$mod_paths_ar;
require IPTables::Parse;
require IPTables::ChainMgr;
return;
}
sub get_psad_mod_paths() {
my @paths = ();
unless (-d $psad_lib_dir) {
my $dir_tmp = $psad_lib_dir;
$dir_tmp =~ s|lib/|lib64/|;
if (-d $dir_tmp) {
$psad_lib_dir = $dir_tmp;
} else {
die "[*] psad lib directory: $psad_lib_dir does not exist, ",
"use --Lib-dir ";
}
}
opendir D, $psad_lib_dir or die "[*] Could not open $psad_lib_dir: $!";
my @dirs = readdir D;
closedir D;
shift @dirs; shift @dirs;
push @paths, $psad_lib_dir;
for my $dir (@dirs) {
### get directories like "/usr/lib/psad/x86_64-linux"
next unless -d "$psad_lib_dir/$dir";
push @paths, "$psad_lib_dir/$dir"
if $dir =~ m|linux| or $dir =~ m|thread|;
}
return \@paths;
}
psad-7c4a910/config_vars.conf 0000664 0000000 0000000 00000000116 12071203757 0016144 0 ustar 00root root 0000000 0000000 psad psad.conf
kmsgsd.c psad.conf
psadwatchd.c psad.conf
psad-7c4a910/config_vars.pl 0000775 0000000 0000000 00000006242 12071203757 0015643 0 ustar 00root root 0000000 0000000 #!/usr/bin/perl -w
#
############################################################################
#
# File: config_vars.pl
#
# Purpose: To provide basic usage validation for cipherdyne.org project
# variables.
#
############################################################################
#
use strict;
my $config_file = 'config_vars.conf';
open C, "< $config_file" or die $!;
my @lines = ;
close C;
my %config = ();
for my $line (@lines) {
next unless $line;
next if $line =~ /^\s*#/;
if ($line =~ /^\s*(\S+)\s+(\S+)/) {
$config{$1}{$2} = '';
}
}
PROG: for my $prog (keys %config) {
unless (-e $prog) {
print "[-] program: $prog does not exist in current directory.\n";
next PROG;
}
open F, "< $prog" or die "[*] Could not open $prog: $!";
my @prog_lines = ;
close F;
my %config_vars = ();
my %used_vars = ();
CONF: for my $config (keys %{$config{$prog}}) {
unless (-e $config) {
print "[-] config: $config for program: $prog does not exist.\n";
next CONF;
}
open F, "< $config" or die "[*] Could not open $config: $!";
my @config_lines = ;
close F;
for my $line (@config_lines) {
next unless $line;
next unless $line =~ /\S/;
next if $line =~ /^\s*#/;
if ($line =~ /^\s*(\S+)\s/) {
$config_vars{$1} = '';
}
}
}
my $line_num = 1;
### see if the program is using an undefined configuration
### variable
for my $line (@prog_lines) {
if ($prog =~ /\.c/) { ### C code file
if ($line =~ m|find_char_var\(\"(\w+)\"|) {
my $var = $1;
unless (defined $config_vars{$var}) {
print "[-] Config var: $var (line $line_num) ",
"is not defined in config files for program: $prog\n";
}
$used_vars{$var} = '';
}
} else {
my $var1 = '';
my $var2 = '';
if ($line =~ m|\$config\{\'(\S+?)\'\}|) {
$var1 = $1;
}
if ($line =~ m|\$cmds\{\'(\S+?)\'\}|) {
$var2 = "$1Cmd";
}
if ($var1) {
unless (defined $config_vars{$var1}) {
print "[-] Config var: $var1 (line $line_num) ",
"is not defined in config files for program: $prog\n";
}
$used_vars{$var1} = '';
}
if ($var2) {
unless (defined $config_vars{$var2}) {
print "[-] Config var: $var2 (line $line_num) ",
"is not defined in config files for program: $prog\n";
}
$used_vars{$var2} = '';
}
}
$line_num++;
}
### see if the config files define a configuration variable
### that is not used by the program
for my $var (sort keys %config_vars) {
unless (defined $used_vars{$var}) {
print "[-] $var is defined in config files, ",
"but not used in $prog\n";
}
}
}
exit 0;
psad-7c4a910/deps/ 0000775 0000000 0000000 00000000000 12071203757 0013732 5 ustar 00root root 0000000 0000000 psad-7c4a910/deps/Bit-Vector/ 0000775 0000000 0000000 00000000000 12071203757 0015710 5 ustar 00root root 0000000 0000000 psad-7c4a910/deps/Bit-Vector/Artistic.txt 0000664 0000000 0000000 00000013737 12071203757 0020246 0 ustar 00root root 0000000 0000000
The "Artistic License"
Preamble
The intent of this document is to state the conditions under which a
Package may be copied, such that the Copyright Holder maintains some
semblance of artistic control over the development of the package,
while giving the users of the package the right to use and distribute
the Package in a more-or-less customary fashion, plus the right to make
reasonable modifications.
Definitions:
"Package" refers to the collection of files distributed by the
Copyright Holder, and derivatives of that collection of files
created through textual modification.
"Standard Version" refers to such a Package if it has not been
modified, or has been modified in accordance with the wishes
of the Copyright Holder as specified below.
"Copyright Holder" is whoever is named in the copyright or
copyrights for the package.
"You" is you, if you're thinking about copying or distributing
this Package.
"Reasonable copying fee" is whatever you can justify on the
basis of media cost, duplication charges, time of people involved,
and so on. (You will not be required to justify it to the
Copyright Holder, but only to the computing community at large
as a market that must bear the fee.)
"Freely Available" means that no fee is charged for the item
itself, though there may be fees involved in handling the item.
It also means that recipients of the item may redistribute it
under the same conditions they received it.
1. You may make and give away verbatim copies of the source form of the
Standard Version of this Package without restriction, provided that you
duplicate all of the original copyright notices and associated disclaimers.
2. You may apply bug fixes, portability fixes and other modifications
derived from the Public Domain or from the Copyright Holder. A Package
modified in such a way shall still be considered the Standard Version.
3. You may otherwise modify your copy of this Package in any way, provided
that you insert a prominent notice in each changed file stating how and
when you changed that file, and provided that you do at least ONE of the
following:
a) place your modifications in the Public Domain or otherwise make them
Freely Available, such as by posting said modifications to Usenet or
an equivalent medium, or placing the modifications on a major archive
site such as uunet.uu.net, or by allowing the Copyright Holder to include
your modifications in the Standard Version of the Package.
b) use the modified Package only within your corporation or organization.
c) rename any non-standard executables so the names do not conflict
with standard executables, which must also be provided, and provide
a separate manual page for each non-standard executable that clearly
documents how it differs from the Standard Version.
d) make other distribution arrangements with the Copyright Holder.
4. You may distribute the programs of this Package in object code or
executable form, provided that you do at least ONE of the following:
a) distribute a Standard Version of the executables and library files,
together with instructions (in the manual page or equivalent) on where
to get the Standard Version.
b) accompany the distribution with the machine-readable source of
the Package with your modifications.
c) give non-standard executables non-standard names, and clearly
document the differences in manual pages (or equivalent), together
with instructions on where to get the Standard Version.
d) make other distribution arrangements with the Copyright Holder.
5. You may charge a reasonable copying fee for any distribution of this
Package. You may charge any fee you choose for support of this
Package. You may not charge a fee for this Package itself. However,
you may distribute this Package in aggregate with other (possibly
commercial) programs as part of a larger (possibly commercial) software
distribution provided that you do not advertise this Package as a
product of your own. You may embed this Package's interpreter within
an executable of yours (by linking); this shall be construed as a mere
form of aggregation, provided that the complete Standard Version of the
interpreter is so embedded.
6. The scripts and library files supplied as input to or produced as
output from the programs of this Package do not automatically fall
under the copyright of this Package, but belong to whoever generated
them, and may be sold commercially, and may be aggregated with this
Package. If such scripts or library files are aggregated with this
Package via the so-called "undump" or "unexec" methods of producing a
binary executable image, then distribution of such an image shall
neither be construed as a distribution of this Package nor shall it
fall under the restrictions of Paragraphs 3 and 4, provided that you do
not represent such an executable image as a Standard Version of this
Package.
7. C subroutines (or comparably compiled subroutines in other
languages) supplied by you and linked into this Package in order to
emulate subroutines and variables of the language defined by this
Package shall not be considered part of this Package, but are the
equivalent of input as in Paragraph 6, provided these subroutines do
not change the language in any way that would cause it to fail the
regression tests for the language.
8. Aggregation of this Package with a commercial distribution is always
permitted provided that the use of this Package is embedded; that is,
when no overt attempt is made to make this Package's interfaces visible
to the end user of the commercial distribution. Such use shall not be
construed as a distribution of this Package.
9. The name of the Copyright Holder may not be used to endorse or promote
products derived from this software without specific prior written permission.
10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
The End
psad-7c4a910/deps/Bit-Vector/BitVector.c 0000664 0000000 0000000 00000341235 12071203757 0017765 0 ustar 00root root 0000000 0000000 #ifndef MODULE_BIT_VECTOR
#define MODULE_BIT_VECTOR
/*****************************************************************************/
/* MODULE NAME: BitVector.c MODULE TYPE: (adt) */
/*****************************************************************************/
/* MODULE IMPORTS: */
/*****************************************************************************/
#include /* MODULE TYPE: (sys) */
#include /* MODULE TYPE: (sys) */
#include /* MODULE TYPE: (sys) */
#include /* MODULE TYPE: (sys) */
#include "ToolBox.h" /* MODULE TYPE: (dat) */
/*****************************************************************************/
/* MODULE INTERFACE: */
/*****************************************************************************/
typedef enum
{
ErrCode_Ok = 0, /* everything went allright */
ErrCode_Type, /* types word and size_t have incompatible sizes */
ErrCode_Bits, /* bits of word and sizeof(word) are inconsistent */
ErrCode_Word, /* size of word is less than 16 bits */
ErrCode_Long, /* size of word is greater than size of long */
ErrCode_Powr, /* number of bits of word is not a power of two */
ErrCode_Loga, /* error in calculation of logarithm */
ErrCode_Null, /* unable to allocate memory */
ErrCode_Indx, /* index out of range */
ErrCode_Ordr, /* minimum > maximum index */
ErrCode_Size, /* bit vector size mismatch */
ErrCode_Pars, /* input string syntax error */
ErrCode_Ovfl, /* numeric overflow error */
ErrCode_Same, /* operands must be distinct */
ErrCode_Expo, /* exponent must be positive */
ErrCode_Zero /* division by zero error */
} ErrCode;
typedef wordptr *listptr;
/* ===> MISCELLANEOUS BASIC FUNCTIONS: <=== */
charptr BitVector_Error (ErrCode error); /* return string for err code */
ErrCode BitVector_Boot (void); /* 0 = ok, 1..7 = error */
N_word BitVector_Size (N_int bits); /* bit vector size (# of words) */
N_word BitVector_Mask (N_int bits); /* bit vector mask (unused bits) */
/* ===> CLASS METHODS: <=== */
charptr BitVector_Version (void); /* return version string */
N_int BitVector_Word_Bits (void); /* return # of bits in machine word */
N_int BitVector_Long_Bits (void); /* return # of bits in unsigned long */
/* ===> CONSTRUCTOR METHODS: <=== */
wordptr BitVector_Create (N_int bits, boolean clear); /* malloc */
listptr BitVector_Create_List(N_int bits, boolean clear, N_int count);
wordptr BitVector_Resize (wordptr oldaddr, N_int bits); /* realloc */
wordptr BitVector_Shadow (wordptr addr); /* make new same size but empty */
wordptr BitVector_Clone (wordptr addr); /* make exact duplicate */
wordptr BitVector_Concat (wordptr X, wordptr Y); /* return concatenation */
/* ===> DESTRUCTOR METHODS: <=== */
void BitVector_Dispose (charptr string); /* string */
void BitVector_Destroy (wordptr addr); /* bitvec */
void BitVector_Destroy_List (listptr list, N_int count); /* list */
/* ===> OBJECT METHODS: <=== */
/* ===> bit vector copy function: */
void BitVector_Copy (wordptr X, wordptr Y); /* X = Y */
/* ===> bit vector initialization: */
void BitVector_Empty (wordptr addr); /* X = {} */
void BitVector_Fill (wordptr addr); /* X = ~{} */
void BitVector_Flip (wordptr addr); /* X = ~X */
void BitVector_Primes (wordptr addr);
/* ===> miscellaneous functions: */
void BitVector_Reverse (wordptr X, wordptr Y);
/* ===> bit vector interval operations and functions: */
void BitVector_Interval_Empty (wordptr addr, N_int lower, N_int upper);
void BitVector_Interval_Fill (wordptr addr, N_int lower, N_int upper);
void BitVector_Interval_Flip (wordptr addr, N_int lower, N_int upper);
void BitVector_Interval_Reverse (wordptr addr, N_int lower, N_int upper);
boolean BitVector_interval_scan_inc (wordptr addr, N_int start,
N_intptr min, N_intptr max);
boolean BitVector_interval_scan_dec (wordptr addr, N_int start,
N_intptr min, N_intptr max);
void BitVector_Interval_Copy (wordptr X, wordptr Y, N_int Xoffset,
N_int Yoffset, N_int length);
wordptr BitVector_Interval_Substitute(wordptr X, wordptr Y,
N_int Xoffset, N_int Xlength,
N_int Yoffset, N_int Ylength);
/* ===> bit vector test functions: */
boolean BitVector_is_empty (wordptr addr); /* X == {} ? */
boolean BitVector_is_full (wordptr addr); /* X == ~{} ? */
boolean BitVector_equal (wordptr X, wordptr Y); /* X == Y ? */
Z_int BitVector_Lexicompare(wordptr X, wordptr Y); /* X Y ? */
Z_int BitVector_Compare (wordptr X, wordptr Y); /* X Y ? */
/* ===> bit vector string conversion functions: */
charptr BitVector_to_Hex (wordptr addr);
ErrCode BitVector_from_Hex (wordptr addr, charptr string);
charptr BitVector_to_Bin (wordptr addr);
ErrCode BitVector_from_Bin (wordptr addr, charptr string);
charptr BitVector_to_Dec (wordptr addr);
ErrCode BitVector_from_Dec (wordptr addr, charptr string);
charptr BitVector_to_Enum (wordptr addr);
ErrCode BitVector_from_Enum (wordptr addr, charptr string);
/* ===> bit vector bit operations, functions & tests: */
void BitVector_Bit_Off (wordptr addr, N_int index); /* X = X \ {x} */
void BitVector_Bit_On (wordptr addr, N_int index); /* X = X + {x} */
boolean BitVector_bit_flip (wordptr addr, N_int index); /* (X+{x})\(X*{x}) */
boolean BitVector_bit_test (wordptr addr, N_int index); /* {x} in X ? */
void BitVector_Bit_Copy (wordptr addr, N_int index, boolean bit);
/* ===> bit vector bit shift & rotate functions: */
void BitVector_LSB (wordptr addr, boolean bit);
void BitVector_MSB (wordptr addr, boolean bit);
boolean BitVector_lsb_ (wordptr addr);
boolean BitVector_msb_ (wordptr addr);
boolean BitVector_rotate_left (wordptr addr);
boolean BitVector_rotate_right (wordptr addr);
boolean BitVector_shift_left (wordptr addr, boolean carry_in);
boolean BitVector_shift_right (wordptr addr, boolean carry_in);
void BitVector_Move_Left (wordptr addr, N_int bits);
void BitVector_Move_Right (wordptr addr, N_int bits);
/* ===> bit vector insert/delete bits: */
void BitVector_Insert (wordptr addr, N_int offset, N_int count,
boolean clear);
void BitVector_Delete (wordptr addr, N_int offset, N_int count,
boolean clear);
/* ===> bit vector arithmetic: */
boolean BitVector_increment (wordptr addr); /* X++ */
boolean BitVector_decrement (wordptr addr); /* X-- */
boolean BitVector_compute (wordptr X, wordptr Y, wordptr Z, boolean minus,
boolean *carry);
boolean BitVector_add (wordptr X, wordptr Y, wordptr Z, boolean *carry);
boolean BitVector_sub (wordptr X, wordptr Y, wordptr Z, boolean *carry);
boolean BitVector_inc (wordptr X, wordptr Y);
boolean BitVector_dec (wordptr X, wordptr Y);
void BitVector_Negate (wordptr X, wordptr Y);
void BitVector_Absolute (wordptr X, wordptr Y);
Z_int BitVector_Sign (wordptr addr);
ErrCode BitVector_Mul_Pos (wordptr X, wordptr Y, wordptr Z, boolean strict);
ErrCode BitVector_Multiply (wordptr X, wordptr Y, wordptr Z);
ErrCode BitVector_Div_Pos (wordptr Q, wordptr X, wordptr Y, wordptr R);
ErrCode BitVector_Divide (wordptr Q, wordptr X, wordptr Y, wordptr R);
ErrCode BitVector_GCD (wordptr X, wordptr Y, wordptr Z);
ErrCode BitVector_GCD2 (wordptr U, wordptr V, wordptr W, /* O */
wordptr X, wordptr Y); /* I */
ErrCode BitVector_Power (wordptr X, wordptr Y, wordptr Z);
/* ===> direct memory access functions: */
void BitVector_Block_Store(wordptr addr, charptr buffer, N_int length);
charptr BitVector_Block_Read (wordptr addr, N_intptr length);
/* ===> word array functions: */
void BitVector_Word_Store (wordptr addr, N_int offset, N_int value);
N_int BitVector_Word_Read (wordptr addr, N_int offset);
void BitVector_Word_Insert(wordptr addr, N_int offset, N_int count,
boolean clear);
void BitVector_Word_Delete(wordptr addr, N_int offset, N_int count,
boolean clear);
/* ===> arbitrary size chunk functions: */
void BitVector_Chunk_Store(wordptr addr, N_int chunksize,
N_int offset, N_long value);
N_long BitVector_Chunk_Read (wordptr addr, N_int chunksize,
N_int offset);
/* ===> set operations: */
void Set_Union (wordptr X, wordptr Y, wordptr Z); /* X = Y + Z */
void Set_Intersection (wordptr X, wordptr Y, wordptr Z); /* X = Y * Z */
void Set_Difference (wordptr X, wordptr Y, wordptr Z); /* X = Y \ Z */
void Set_ExclusiveOr (wordptr X, wordptr Y, wordptr Z); /*(Y+Z)\(Y*Z)*/
void Set_Complement (wordptr X, wordptr Y); /* X = ~Y */
/* ===> set functions: */
boolean Set_subset (wordptr X, wordptr Y); /* X in Y ? */
N_int Set_Norm (wordptr addr); /* = | X | */
N_int Set_Norm2 (wordptr addr); /* = | X | */
N_int Set_Norm3 (wordptr addr); /* = | X | */
Z_long Set_Min (wordptr addr); /* = min(X) */
Z_long Set_Max (wordptr addr); /* = max(X) */
/* ===> matrix-of-booleans operations: */
void Matrix_Multiplication(wordptr X, N_int rowsX, N_int colsX,
wordptr Y, N_int rowsY, N_int colsY,
wordptr Z, N_int rowsZ, N_int colsZ);
void Matrix_Product (wordptr X, N_int rowsX, N_int colsX,
wordptr Y, N_int rowsY, N_int colsY,
wordptr Z, N_int rowsZ, N_int colsZ);
void Matrix_Closure (wordptr addr, N_int rows, N_int cols);
void Matrix_Transpose (wordptr X, N_int rowsX, N_int colsX,
wordptr Y, N_int rowsY, N_int colsY);
/*****************************************************************************/
/* MODULE RESOURCES: */
/*****************************************************************************/
#define bits_(BitVector) *(BitVector-3)
#define size_(BitVector) *(BitVector-2)
#define mask_(BitVector) *(BitVector-1)
#define ERRCODE_TYPE "sizeof(word) > sizeof(size_t)"
#define ERRCODE_BITS "bits(word) != sizeof(word)*8"
#define ERRCODE_WORD "bits(word) < 16"
#define ERRCODE_LONG "bits(word) > bits(long)"
#define ERRCODE_POWR "bits(word) != 2^x"
#define ERRCODE_LOGA "bits(word) != 2^ld(bits(word))"
#define ERRCODE_NULL "unable to allocate memory"
#define ERRCODE_INDX "index out of range"
#define ERRCODE_ORDR "minimum > maximum index"
#define ERRCODE_SIZE "bit vector size mismatch"
#define ERRCODE_PARS "input string syntax error"
#define ERRCODE_OVFL "numeric overflow error"
#define ERRCODE_SAME "result vector(s) must be distinct"
#define ERRCODE_EXPO "exponent must be positive"
#define ERRCODE_ZERO "division by zero error"
#define ERRCODE_OOPS "unexpected internal error - please contact author"
const N_int BitVector_BYTENORM[256] =
{
0x00, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02, 0x03,
0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, /* 0x00 */
0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04,
0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, /* 0x10 */
0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04,
0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, /* 0x20 */
0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0x30 */
0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04,
0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, /* 0x40 */
0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0x50 */
0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0x60 */
0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, /* 0x70 */
0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04,
0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, /* 0x80 */
0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0x90 */
0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0xA0 */
0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, /* 0xB0 */
0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0xC0 */
0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, /* 0xD0 */
0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, /* 0xE0 */
0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07,
0x05, 0x06, 0x06, 0x07, 0x06, 0x07, 0x07, 0x08 /* 0xF0 */
};
/*****************************************************************************/
/* MODULE IMPLEMENTATION: */
/*****************************************************************************/
/**********************************************/
/* global implementation-intrinsic constants: */
/**********************************************/
#define BIT_VECTOR_HIDDEN_WORDS 3
/*****************************************************************/
/* global machine-dependent constants (set by "BitVector_Boot"): */
/*****************************************************************/
static N_word BITS; /* = # of bits in machine word (must be power of 2) */
static N_word MODMASK; /* = BITS - 1 (mask for calculating modulo BITS) */
static N_word LOGBITS; /* = ld(BITS) (logarithmus dualis) */
static N_word FACTOR; /* = ld(BITS / 8) (ld of # of bytes) */
static N_word LSB = 1; /* = mask for least significant bit */
static N_word MSB; /* = mask for most significant bit */
static N_word LONGBITS; /* = # of bits in unsigned long */
static N_word LOG10; /* = logarithm to base 10 of BITS - 1 */
static N_word EXP10; /* = largest possible power of 10 in signed int */
/********************************************************************/
/* global bit mask table for fast access (set by "BitVector_Boot"): */
/********************************************************************/
static wordptr BITMASKTAB;
/*****************************/
/* global macro definitions: */
/*****************************/
#define BIT_VECTOR_ZERO_WORDS(target,count) \
while (count-- > 0) *target++ = 0;
#define BIT_VECTOR_FILL_WORDS(target,fill,count) \
while (count-- > 0) *target++ = fill;
#define BIT_VECTOR_FLIP_WORDS(target,flip,count) \
while (count-- > 0) *target++ ^= flip;
#define BIT_VECTOR_COPY_WORDS(target,source,count) \
while (count-- > 0) *target++ = *source++;
#define BIT_VECTOR_BACK_WORDS(target,source,count) \
{ target += count; source += count; while (count-- > 0) *--target = *--source; }
#define BIT_VECTOR_CLR_BIT(address,index) \
*(address+(index>>LOGBITS)) &= NOT BITMASKTAB[index AND MODMASK];
#define BIT_VECTOR_SET_BIT(address,index) \
*(address+(index>>LOGBITS)) |= BITMASKTAB[index AND MODMASK];
#define BIT_VECTOR_TST_BIT(address,index) \
((*(address+(index>>LOGBITS)) AND BITMASKTAB[index AND MODMASK]) != 0)
#define BIT_VECTOR_FLP_BIT(address,index,mask) \
(mask = BITMASKTAB[index AND MODMASK]), \
(((*(addr+(index>>LOGBITS)) ^= mask) AND mask) != 0)
#define BIT_VECTOR_DIGITIZE(type,value,digit) \
value = (type) ((digit = value) / 10); \
digit -= value * 10; \
digit += (type) '0';
/*********************************************************/
/* private low-level functions (potentially dangerous!): */
/*********************************************************/
static N_word power10(N_word x)
{
N_word y = 1;
while (x-- > 0) y *= 10;
return(y);
}
static void BIT_VECTOR_zro_words(wordptr addr, N_word count)
{
BIT_VECTOR_ZERO_WORDS(addr,count)
}
static void BIT_VECTOR_cpy_words(wordptr target, wordptr source, N_word count)
{
BIT_VECTOR_COPY_WORDS(target,source,count)
}
static void BIT_VECTOR_mov_words(wordptr target, wordptr source, N_word count)
{
if (target != source)
{
if (target < source) BIT_VECTOR_COPY_WORDS(target,source,count)
else BIT_VECTOR_BACK_WORDS(target,source,count)
}
}
static void BIT_VECTOR_ins_words(wordptr addr, N_word total, N_word count,
boolean clear)
{
N_word length;
if ((total > 0) and (count > 0))
{
if (count > total) count = total;
length = total - count;
if (length > 0) BIT_VECTOR_mov_words(addr+count,addr,length);
if (clear) BIT_VECTOR_zro_words(addr,count);
}
}
static void BIT_VECTOR_del_words(wordptr addr, N_word total, N_word count,
boolean clear)
{
N_word length;
if ((total > 0) and (count > 0))
{
if (count > total) count = total;
length = total - count;
if (length > 0) BIT_VECTOR_mov_words(addr,addr+count,length);
if (clear) BIT_VECTOR_zro_words(addr+length,count);
}
}
static void BIT_VECTOR_reverse(charptr string, N_word length)
{
charptr last;
N_char temp;
if (length > 1)
{
last = string + length - 1;
while (string < last)
{
temp = *string;
*string = *last;
*last = temp;
string++;
last--;
}
}
}
static N_word BIT_VECTOR_int2str(charptr string, N_word value)
{
N_word length;
N_word digit;
charptr work;
work = string;
if (value > 0)
{
length = 0;
while (value > 0)
{
BIT_VECTOR_DIGITIZE(N_word,value,digit)
*work++ = (N_char) digit;
length++;
}
BIT_VECTOR_reverse(string,length);
}
else
{
length = 1;
*work++ = (N_char) '0';
}
return(length);
}
static N_word BIT_VECTOR_str2int(charptr string, N_word *value)
{
N_word length;
N_word digit;
*value = 0;
length = 0;
digit = (N_word) *string++;
/* separate because isdigit() is likely a macro! */
while (isdigit((int)digit) != 0)
{
length++;
digit -= (N_word) '0';
if (*value) *value *= 10;
*value += digit;
digit = (N_word) *string++;
}
return(length);
}
/********************************************/
/* routine to convert error code to string: */
/********************************************/
charptr BitVector_Error(ErrCode error)
{
switch (error)
{
case ErrCode_Ok: return( (charptr) NULL ); break;
case ErrCode_Type: return( (charptr) ERRCODE_TYPE ); break;
case ErrCode_Bits: return( (charptr) ERRCODE_BITS ); break;
case ErrCode_Word: return( (charptr) ERRCODE_WORD ); break;
case ErrCode_Long: return( (charptr) ERRCODE_LONG ); break;
case ErrCode_Powr: return( (charptr) ERRCODE_POWR ); break;
case ErrCode_Loga: return( (charptr) ERRCODE_LOGA ); break;
case ErrCode_Null: return( (charptr) ERRCODE_NULL ); break;
case ErrCode_Indx: return( (charptr) ERRCODE_INDX ); break;
case ErrCode_Ordr: return( (charptr) ERRCODE_ORDR ); break;
case ErrCode_Size: return( (charptr) ERRCODE_SIZE ); break;
case ErrCode_Pars: return( (charptr) ERRCODE_PARS ); break;
case ErrCode_Ovfl: return( (charptr) ERRCODE_OVFL ); break;
case ErrCode_Same: return( (charptr) ERRCODE_SAME ); break;
case ErrCode_Expo: return( (charptr) ERRCODE_EXPO ); break;
case ErrCode_Zero: return( (charptr) ERRCODE_ZERO ); break;
default: return( (charptr) ERRCODE_OOPS ); break;
}
}
/*****************************************/
/* automatic self-configuration routine: */
/*****************************************/
/*******************************************************/
/* */
/* MUST be called once prior to any other function */
/* to initialize the machine dependent constants */
/* of this package! (But call only ONCE, or you */
/* will suffer memory leaks!) */
/* */
/*******************************************************/
ErrCode BitVector_Boot(void)
{
N_long longsample = 1L;
N_word sample = LSB;
N_word lsb;
if (sizeof(N_word) > sizeof(size_t)) return(ErrCode_Type);
BITS = 1;
while (sample <<= 1) BITS++; /* determine # of bits in a machine word */
if (BITS != (sizeof(N_word) << 3)) return(ErrCode_Bits);
if (BITS < 16) return(ErrCode_Word);
LONGBITS = 1;
while (longsample <<= 1) LONGBITS++; /* = # of bits in an unsigned long */
if (BITS > LONGBITS) return(ErrCode_Long);
LOGBITS = 0;
sample = BITS;
lsb = (sample AND LSB);
while ((sample >>= 1) and (not lsb))
{
LOGBITS++;
lsb = (sample AND LSB);
}
if (sample) return(ErrCode_Powr); /* # of bits is not a power of 2! */
if (BITS != (LSB << LOGBITS)) return(ErrCode_Loga);
MODMASK = BITS - 1;
FACTOR = LOGBITS - 3; /* ld(BITS / 8) = ld(BITS) - ld(8) = ld(BITS) - 3 */
MSB = (LSB << MODMASK);
BITMASKTAB = (wordptr) malloc((size_t) (BITS << FACTOR));
if (BITMASKTAB == NULL) return(ErrCode_Null);
for ( sample = 0; sample < BITS; sample++ )
{
BITMASKTAB[sample] = (LSB << sample);
}
LOG10 = (N_word) (MODMASK * 0.30103); /* = (BITS - 1) * ( ln 2 / ln 10 ) */
EXP10 = power10(LOG10);
return(ErrCode_Ok);
}
N_word BitVector_Size(N_int bits) /* bit vector size (# of words) */
{
N_word size;
size = bits >> LOGBITS;
if (bits AND MODMASK) size++;
return(size);
}
N_word BitVector_Mask(N_int bits) /* bit vector mask (unused bits) */
{
N_word mask;
mask = bits AND MODMASK;
if (mask) mask = (N_word) ~(~0L << mask); else mask = (N_word) ~0L;
return(mask);
}
charptr BitVector_Version(void)
{
return((charptr)"6.4");
}
N_int BitVector_Word_Bits(void)
{
return(BITS);
}
N_int BitVector_Long_Bits(void)
{
return(LONGBITS);
}
/********************************************************************/
/* */
/* WARNING: Do not "free()" constant character strings, i.e., */
/* don't call "BitVector_Dispose()" for strings returned */
/* by "BitVector_Error()" or "BitVector_Version()"! */
/* */
/* ONLY call this function for strings allocated with "malloc()", */
/* i.e., the strings returned by the functions "BitVector_to_*()" */
/* and "BitVector_Block_Read()"! */
/* */
/********************************************************************/
void BitVector_Dispose(charptr string) /* free string */
{
if (string != NULL) free((voidptr) string);
}
void BitVector_Destroy(wordptr addr) /* free bitvec */
{
if (addr != NULL)
{
addr -= BIT_VECTOR_HIDDEN_WORDS;
free((voidptr) addr);
}
}
void BitVector_Destroy_List(listptr list, N_int count) /* free list */
{
listptr slot;
if (list != NULL)
{
slot = list;
while (count-- > 0)
{
BitVector_Destroy(*slot++);
}
free((voidptr) list);
}
}
wordptr BitVector_Create(N_int bits, boolean clear) /* malloc */
{
N_word size;
N_word mask;
N_word bytes;
wordptr addr;
wordptr zero;
size = BitVector_Size(bits);
mask = BitVector_Mask(bits);
bytes = (size + BIT_VECTOR_HIDDEN_WORDS) << FACTOR;
addr = (wordptr) malloc((size_t) bytes);
if (addr != NULL)
{
*addr++ = bits;
*addr++ = size;
*addr++ = mask;
if (clear)
{
zero = addr;
BIT_VECTOR_ZERO_WORDS(zero,size)
}
}
return(addr);
}
listptr BitVector_Create_List(N_int bits, boolean clear, N_int count)
{
listptr list = NULL;
listptr slot;
wordptr addr;
N_int i;
if (count > 0)
{
list = (listptr) malloc(sizeof(wordptr) * count);
if (list != NULL)
{
slot = list;
for ( i = 0; i < count; i++ )
{
addr = BitVector_Create(bits,clear);
if (addr == NULL)
{
BitVector_Destroy_List(list,i);
return(NULL);
}
*slot++ = addr;
}
}
}
return(list);
}
wordptr BitVector_Resize(wordptr oldaddr, N_int bits) /* realloc */
{
N_word bytes;
N_word oldsize;
N_word oldmask;
N_word newsize;
N_word newmask;
wordptr newaddr;
wordptr source;
wordptr target;
oldsize = size_(oldaddr);
oldmask = mask_(oldaddr);
newsize = BitVector_Size(bits);
newmask = BitVector_Mask(bits);
if (oldsize > 0) *(oldaddr+oldsize-1) &= oldmask;
if (newsize <= oldsize)
{
newaddr = oldaddr;
bits_(newaddr) = bits;
size_(newaddr) = newsize;
mask_(newaddr) = newmask;
if (newsize > 0) *(newaddr+newsize-1) &= newmask;
}
else
{
bytes = (newsize + BIT_VECTOR_HIDDEN_WORDS) << FACTOR;
newaddr = (wordptr) malloc((size_t) bytes);
if (newaddr != NULL)
{
*newaddr++ = bits;
*newaddr++ = newsize;
*newaddr++ = newmask;
target = newaddr;
source = oldaddr;
newsize -= oldsize;
BIT_VECTOR_COPY_WORDS(target,source,oldsize)
BIT_VECTOR_ZERO_WORDS(target,newsize)
}
BitVector_Destroy(oldaddr);
}
return(newaddr);
}
wordptr BitVector_Shadow(wordptr addr) /* makes new, same size but empty */
{
return( BitVector_Create(bits_(addr),true) );
}
wordptr BitVector_Clone(wordptr addr) /* makes exact duplicate */
{
N_word bits;
wordptr twin;
bits = bits_(addr);
twin = BitVector_Create(bits,false);
if ((twin != NULL) and (bits > 0))
BIT_VECTOR_cpy_words(twin,addr,size_(addr));
return(twin);
}
wordptr BitVector_Concat(wordptr X, wordptr Y) /* returns concatenation */
{
/* BEWARE that X = most significant part, Y = least significant part! */
N_word bitsX;
N_word bitsY;
N_word bitsZ;
wordptr Z;
bitsX = bits_(X);
bitsY = bits_(Y);
bitsZ = bitsX + bitsY;
Z = BitVector_Create(bitsZ,false);
if ((Z != NULL) and (bitsZ > 0))
{
BIT_VECTOR_cpy_words(Z,Y,size_(Y));
BitVector_Interval_Copy(Z,X,bitsY,0,bitsX);
*(Z+size_(Z)-1) &= mask_(Z);
}
return(Z);
}
void BitVector_Copy(wordptr X, wordptr Y) /* X = Y */
{
N_word sizeX = size_(X);
N_word sizeY = size_(Y);
N_word maskX = mask_(X);
N_word maskY = mask_(Y);
N_word fill = 0;
wordptr lastX;
wordptr lastY;
if ((X != Y) and (sizeX > 0))
{
lastX = X + sizeX - 1;
if (sizeY > 0)
{
lastY = Y + sizeY - 1;
if ( (*lastY AND (maskY AND NOT (maskY >> 1))) == 0 ) *lastY &= maskY;
else
{
fill = (N_word) ~0L;
*lastY |= NOT maskY;
}
while ((sizeX > 0) and (sizeY > 0))
{
*X++ = *Y++;
sizeX--;
sizeY--;
}
*lastY &= maskY;
}
while (sizeX-- > 0) *X++ = fill;
*lastX &= maskX;
}
}
void BitVector_Empty(wordptr addr) /* X = {} clr all */
{
N_word size = size_(addr);
BIT_VECTOR_ZERO_WORDS(addr,size)
}
void BitVector_Fill(wordptr addr) /* X = ~{} set all */
{
N_word size = size_(addr);
N_word mask = mask_(addr);
N_word fill = (N_word) ~0L;
if (size > 0)
{
BIT_VECTOR_FILL_WORDS(addr,fill,size)
*(--addr) &= mask;
}
}
void BitVector_Flip(wordptr addr) /* X = ~X flip all */
{
N_word size = size_(addr);
N_word mask = mask_(addr);
N_word flip = (N_word) ~0L;
if (size > 0)
{
BIT_VECTOR_FLIP_WORDS(addr,flip,size)
*(--addr) &= mask;
}
}
void BitVector_Primes(wordptr addr)
{
N_word bits = bits_(addr);
N_word size = size_(addr);
wordptr work;
N_word temp;
N_word i,j;
if (size > 0)
{
temp = 0xAAAA;
i = BITS >> 4;
while (--i > 0)
{
temp <<= 16;
temp |= 0xAAAA;
}
i = size;
work = addr;
*work++ = temp XOR 0x0006;
while (--i > 0) *work++ = temp;
for ( i = 3; (j = i * i) < bits; i += 2 )
{
for ( ; j < bits; j += i ) BIT_VECTOR_CLR_BIT(addr,j)
}
*(addr+size-1) &= mask_(addr);
}
}
void BitVector_Reverse(wordptr X, wordptr Y)
{
N_word bits = bits_(X);
N_word mask;
N_word bit;
N_word value;
if (bits > 0)
{
if (X == Y) BitVector_Interval_Reverse(X,0,bits-1);
else if (bits == bits_(Y))
{
/* mask = mask_(Y); */
/* mask &= NOT (mask >> 1); */
mask = BITMASKTAB[(bits-1) AND MODMASK];
Y += size_(Y) - 1;
value = 0;
bit = LSB;
while (bits-- > 0)
{
if ((*Y AND mask) != 0)
{
value |= bit;
}
if (not (mask >>= 1))
{
Y--;
mask = MSB;
}
if (not (bit <<= 1))
{
*X++ = value;
value = 0;
bit = LSB;
}
}
if (bit > LSB) *X = value;
}
}
}
void BitVector_Interval_Empty(wordptr addr, N_int lower, N_int upper)
{ /* X = X \ [lower..upper] */
N_word bits = bits_(addr);
N_word size = size_(addr);
wordptr loaddr;
wordptr hiaddr;
N_word lobase;
N_word hibase;
N_word lomask;
N_word himask;
N_word diff;
if ((size > 0) and (lower < bits) and (upper < bits) and (lower <= upper))
{
lobase = lower >> LOGBITS;
hibase = upper >> LOGBITS;
diff = hibase - lobase;
loaddr = addr + lobase;
hiaddr = addr + hibase;
lomask = (N_word) (~0L << (lower AND MODMASK));
himask = (N_word) ~((~0L << (upper AND MODMASK)) << 1);
if (diff == 0)
{
*loaddr &= NOT (lomask AND himask);
}
else
{
*loaddr++ &= NOT lomask;
while (--diff > 0)
{
*loaddr++ = 0;
}
*hiaddr &= NOT himask;
}
}
}
void BitVector_Interval_Fill(wordptr addr, N_int lower, N_int upper)
{ /* X = X + [lower..upper] */
N_word bits = bits_(addr);
N_word size = size_(addr);
N_word fill = (N_word) ~0L;
wordptr loaddr;
wordptr hiaddr;
N_word lobase;
N_word hibase;
N_word lomask;
N_word himask;
N_word diff;
if ((size > 0) and (lower < bits) and (upper < bits) and (lower <= upper))
{
lobase = lower >> LOGBITS;
hibase = upper >> LOGBITS;
diff = hibase - lobase;
loaddr = addr + lobase;
hiaddr = addr + hibase;
lomask = (N_word) (~0L << (lower AND MODMASK));
himask = (N_word) ~((~0L << (upper AND MODMASK)) << 1);
if (diff == 0)
{
*loaddr |= (lomask AND himask);
}
else
{
*loaddr++ |= lomask;
while (--diff > 0)
{
*loaddr++ = fill;
}
*hiaddr |= himask;
}
*(addr+size-1) &= mask_(addr);
}
}
void BitVector_Interval_Flip(wordptr addr, N_int lower, N_int upper)
{ /* X = X ^ [lower..upper] */
N_word bits = bits_(addr);
N_word size = size_(addr);
N_word flip = (N_word) ~0L;
wordptr loaddr;
wordptr hiaddr;
N_word lobase;
N_word hibase;
N_word lomask;
N_word himask;
N_word diff;
if ((size > 0) and (lower < bits) and (upper < bits) and (lower <= upper))
{
lobase = lower >> LOGBITS;
hibase = upper >> LOGBITS;
diff = hibase - lobase;
loaddr = addr + lobase;
hiaddr = addr + hibase;
lomask = (N_word) (~0L << (lower AND MODMASK));
himask = (N_word) ~((~0L << (upper AND MODMASK)) << 1);
if (diff == 0)
{
*loaddr ^= (lomask AND himask);
}
else
{
*loaddr++ ^= lomask;
while (--diff > 0)
{
*loaddr++ ^= flip;
}
*hiaddr ^= himask;
}
*(addr+size-1) &= mask_(addr);
}
}
void BitVector_Interval_Reverse(wordptr addr, N_int lower, N_int upper)
{
N_word bits = bits_(addr);
wordptr loaddr;
wordptr hiaddr;
N_word lomask;
N_word himask;
if ((bits > 0) and (lower < bits) and (upper < bits) and (lower < upper))
{
loaddr = addr + (lower >> LOGBITS);
hiaddr = addr + (upper >> LOGBITS);
lomask = BITMASKTAB[lower AND MODMASK];
himask = BITMASKTAB[upper AND MODMASK];
for ( bits = upper - lower + 1; bits > 1; bits -= 2 )
{
if (((*loaddr AND lomask) != 0) XOR ((*hiaddr AND himask) != 0))
{
*loaddr ^= lomask; /* swap bits only if they differ! */
*hiaddr ^= himask;
}
if (not (lomask <<= 1))
{
lomask = LSB;
loaddr++;
}
if (not (himask >>= 1))
{
himask = MSB;
hiaddr--;
}
}
}
}
boolean BitVector_interval_scan_inc(wordptr addr, N_int start,
N_intptr min, N_intptr max)
{
N_word size = size_(addr);
N_word mask = mask_(addr);
N_word offset;
N_word bitmask;
N_word value;
boolean empty;
if ((size == 0) or (start >= bits_(addr))) return(false);
*min = start;
*max = start;
offset = start >> LOGBITS;
*(addr+size-1) &= mask;
addr += offset;
size -= offset;
bitmask = BITMASKTAB[start AND MODMASK];
mask = NOT (bitmask OR (bitmask - 1));
value = *addr++;
if ((value AND bitmask) == 0)
{
value &= mask;
if (value == 0)
{
offset++;
empty = true;
while (empty and (--size > 0))
{
if ((value = *addr++)) empty = false; else offset++;
}
if (empty) return(false);
}
start = offset << LOGBITS;
bitmask = LSB;
mask = value;
while (not (mask AND LSB))
{
bitmask <<= 1;
mask >>= 1;
start++;
}
mask = NOT (bitmask OR (bitmask - 1));
*min = start;
*max = start;
}
value = NOT value;
value &= mask;
if (value == 0)
{
offset++;
empty = true;
while (empty and (--size > 0))
{
if ((value = NOT *addr++)) empty = false; else offset++;
}
if (empty) value = LSB;
}
start = offset << LOGBITS;
while (not (value AND LSB))
{
value >>= 1;
start++;
}
*max = --start;
return(true);
}
boolean BitVector_interval_scan_dec(wordptr addr, N_int start,
N_intptr min, N_intptr max)
{
N_word size = size_(addr);
N_word mask = mask_(addr);
N_word offset;
N_word bitmask;
N_word value;
boolean empty;
if ((size == 0) or (start >= bits_(addr))) return(false);
*min = start;
*max = start;
offset = start >> LOGBITS;
if (offset >= size) return(false);
*(addr+size-1) &= mask;
addr += offset;
size = ++offset;
bitmask = BITMASKTAB[start AND MODMASK];
mask = (bitmask - 1);
value = *addr--;
if ((value AND bitmask) == 0)
{
value &= mask;
if (value == 0)
{
offset--;
empty = true;
while (empty and (--size > 0))
{
if ((value = *addr--)) empty = false; else offset--;
}
if (empty) return(false);
}
start = offset << LOGBITS;
bitmask = MSB;
mask = value;
while (not (mask AND MSB))
{
bitmask >>= 1;
mask <<= 1;
start--;
}
mask = (bitmask - 1);
*max = --start;
*min = start;
}
value = NOT value;
value &= mask;
if (value == 0)
{
offset--;
empty = true;
while (empty and (--size > 0))
{
if ((value = NOT *addr--)) empty = false; else offset--;
}
if (empty) value = MSB;
}
start = offset << LOGBITS;
while (not (value AND MSB))
{
value <<= 1;
start--;
}
*min = start;
return(true);
}
void BitVector_Interval_Copy(wordptr X, wordptr Y, N_int Xoffset,
N_int Yoffset, N_int length)
{
N_word bitsX = bits_(X);
N_word bitsY = bits_(Y);
N_word source = 0; /* silence compiler warning */
N_word target = 0; /* silence compiler warning */
N_word s_lo_base;
N_word s_hi_base;
N_word s_lo_bit;
N_word s_hi_bit;
N_word s_base;
N_word s_lower = 0; /* silence compiler warning */
N_word s_upper = 0; /* silence compiler warning */
N_word s_bits;
N_word s_min;
N_word s_max;
N_word t_lo_base;
N_word t_hi_base;
N_word t_lo_bit;
N_word t_hi_bit;
N_word t_base;
N_word t_lower = 0; /* silence compiler warning */
N_word t_upper = 0; /* silence compiler warning */
N_word t_bits;
N_word t_min;
N_word mask;
N_word bits;
N_word select;
boolean ascending;
boolean notfirst;
wordptr Z = X;
if ((length > 0) and (Xoffset < bitsX) and (Yoffset < bitsY))
{
if ((Xoffset + length) > bitsX) length = bitsX - Xoffset;
if ((Yoffset + length) > bitsY) length = bitsY - Yoffset;
ascending = (Xoffset <= Yoffset);
s_lo_base = Yoffset >> LOGBITS;
s_lo_bit = Yoffset AND MODMASK;
Yoffset += --length;
s_hi_base = Yoffset >> LOGBITS;
s_hi_bit = Yoffset AND MODMASK;
t_lo_base = Xoffset >> LOGBITS;
t_lo_bit = Xoffset AND MODMASK;
Xoffset += length;
t_hi_base = Xoffset >> LOGBITS;
t_hi_bit = Xoffset AND MODMASK;
if (ascending)
{
s_base = s_lo_base;
t_base = t_lo_base;
}
else
{
s_base = s_hi_base;
t_base = t_hi_base;
}
s_bits = 0;
t_bits = 0;
Y += s_base;
X += t_base;
notfirst = false;
while (true)
{
if (t_bits == 0)
{
if (notfirst)
{
*X = target;
if (ascending)
{
if (t_base == t_hi_base) break;
t_base++;
X++;
}
else
{
if (t_base == t_lo_base) break;
t_base--;
X--;
}
}
select = ((t_base == t_hi_base) << 1) OR (t_base == t_lo_base);
switch (select)
{
case 0:
t_lower = 0;
t_upper = BITS - 1;
t_bits = BITS;
target = 0;
break;
case 1:
t_lower = t_lo_bit;
t_upper = BITS - 1;
t_bits = BITS - t_lo_bit;
mask = (N_word) (~0L << t_lower);
target = *X AND NOT mask;
break;
case 2:
t_lower = 0;
t_upper = t_hi_bit;
t_bits = t_hi_bit + 1;
mask = (N_word) ((~0L << t_upper) << 1);
target = *X AND mask;
break;
case 3:
t_lower = t_lo_bit;
t_upper = t_hi_bit;
t_bits = t_hi_bit - t_lo_bit + 1;
mask = (N_word) (~0L << t_lower);
mask &= (N_word) ~((~0L << t_upper) << 1);
target = *X AND NOT mask;
break;
}
}
if (s_bits == 0)
{
if (notfirst)
{
if (ascending)
{
if (s_base == s_hi_base) break;
s_base++;
Y++;
}
else
{
if (s_base == s_lo_base) break;
s_base--;
Y--;
}
}
source = *Y;
select = ((s_base == s_hi_base) << 1) OR (s_base == s_lo_base);
switch (select)
{
case 0:
s_lower = 0;
s_upper = BITS - 1;
s_bits = BITS;
break;
case 1:
s_lower = s_lo_bit;
s_upper = BITS - 1;
s_bits = BITS - s_lo_bit;
break;
case 2:
s_lower = 0;
s_upper = s_hi_bit;
s_bits = s_hi_bit + 1;
break;
case 3:
s_lower = s_lo_bit;
s_upper = s_hi_bit;
s_bits = s_hi_bit - s_lo_bit + 1;
break;
}
}
notfirst = true;
if (s_bits > t_bits)
{
bits = t_bits - 1;
if (ascending)
{
s_min = s_lower;
s_max = s_lower + bits;
}
else
{
s_max = s_upper;
s_min = s_upper - bits;
}
t_min = t_lower;
}
else
{
bits = s_bits - 1;
if (ascending) t_min = t_lower;
else t_min = t_upper - bits;
s_min = s_lower;
s_max = s_upper;
}
bits++;
mask = (N_word) (~0L << s_min);
mask &= (N_word) ~((~0L << s_max) << 1);
if (s_min == t_min) target |= (source AND mask);
else
{
if (s_min < t_min) target |= (source AND mask) << (t_min-s_min);
else target |= (source AND mask) >> (s_min-t_min);
}
if (ascending)
{
s_lower += bits;
t_lower += bits;
}
else
{
s_upper -= bits;
t_upper -= bits;
}
s_bits -= bits;
t_bits -= bits;
}
*(Z+size_(Z)-1) &= mask_(Z);
}
}
wordptr BitVector_Interval_Substitute(wordptr X, wordptr Y,
N_int Xoffset, N_int Xlength,
N_int Yoffset, N_int Ylength)
{
N_word Xbits = bits_(X);
N_word Ybits = bits_(Y);
N_word limit;
N_word diff;
if ((Xoffset <= Xbits) and (Yoffset <= Ybits))
{
limit = Xoffset + Xlength;
if (limit > Xbits)
{
limit = Xbits;
Xlength = Xbits - Xoffset;
}
if ((Yoffset + Ylength) > Ybits)
{
Ylength = Ybits - Yoffset;
}
if (Xlength == Ylength)
{
if ((Ylength > 0) and ((X != Y) or (Xoffset != Yoffset)))
{
BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength);
}
}
else /* Xlength != Ylength */
{
if (Xlength > Ylength)
{
diff = Xlength - Ylength;
if (Ylength > 0) BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength);
if (limit < Xbits) BitVector_Delete(X,Xoffset+Ylength,diff,false);
if ((X = BitVector_Resize(X,Xbits-diff)) == NULL) return(NULL);
}
else /* Ylength > Xlength ==> Ylength > 0 */
{
diff = Ylength - Xlength;
if (X != Y)
{
if ((X = BitVector_Resize(X,Xbits+diff)) == NULL) return(NULL);
if (limit < Xbits) BitVector_Insert(X,limit,diff,false);
BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength);
}
else /* in-place */
{
if ((Y = X = BitVector_Resize(X,Xbits+diff)) == NULL) return(NULL);
if (limit >= Xbits)
{
BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength);
}
else /* limit < Xbits */
{
BitVector_Insert(X,limit,diff,false);
if ((Yoffset+Ylength) <= limit)
{
BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength);
}
else /* overlaps or lies above critical area */
{
if (limit <= Yoffset)
{
Yoffset += diff;
BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength);
}
else /* Yoffset < limit */
{
Xlength = limit - Yoffset;
BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Xlength);
Yoffset = Xoffset + Ylength; /* = limit + diff */
Xoffset += Xlength;
Ylength -= Xlength;
BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength);
}
}
}
}
}
}
}
return(X);
}
boolean BitVector_is_empty(wordptr addr) /* X == {} ? */
{
N_word size = size_(addr);
boolean r = true;
if (size > 0)
{
*(addr+size-1) &= mask_(addr);
while (r and (size-- > 0)) r = ( *addr++ == 0 );
}
return(r);
}
boolean BitVector_is_full(wordptr addr) /* X == ~{} ? */
{
N_word size = size_(addr);
N_word mask = mask_(addr);
boolean r = false;
wordptr last;
if (size > 0)
{
r = true;
last = addr + size - 1;
*last |= NOT mask;
while (r and (size-- > 0)) r = ( NOT *addr++ == 0 );
*last &= mask;
}
return(r);
}
boolean BitVector_equal(wordptr X, wordptr Y) /* X == Y ? */
{
N_word size = size_(X);
N_word mask = mask_(X);
boolean r = false;
if (bits_(X) == bits_(Y))
{
r = true;
if (size > 0)
{
*(X+size-1) &= mask;
*(Y+size-1) &= mask;
while (r and (size-- > 0)) r = (*X++ == *Y++);
}
}
return(r);
}
Z_int BitVector_Lexicompare(wordptr X, wordptr Y) /* X Y ? */
{ /* unsigned */
N_word bitsX = bits_(X);
N_word bitsY = bits_(Y);
N_word size = size_(X);
boolean r = true;
if (bitsX == bitsY)
{
if (size > 0)
{
X += size;
Y += size;
while (r and (size-- > 0)) r = (*(--X) == *(--Y));
}
if (r) return((Z_int) 0);
else
{
if (*X < *Y) return((Z_int) -1); else return((Z_int) 1);
}
}
else
{
if (bitsX < bitsY) return((Z_int) -1); else return((Z_int) 1);
}
}
Z_int BitVector_Compare(wordptr X, wordptr Y) /* X Y ? */
{ /* signed */
N_word bitsX = bits_(X);
N_word bitsY = bits_(Y);
N_word size = size_(X);
N_word mask = mask_(X);
N_word sign;
boolean r = true;
if (bitsX == bitsY)
{
if (size > 0)
{
X += size;
Y += size;
mask &= NOT (mask >> 1);
if ((sign = (*(X-1) AND mask)) != (*(Y-1) AND mask))
{
if (sign) return((Z_int) -1); else return((Z_int) 1);
}
while (r and (size-- > 0)) r = (*(--X) == *(--Y));
}
if (r) return((Z_int) 0);
else
{
if (*X < *Y) return((Z_int) -1); else return((Z_int) 1);
}
}
else
{
if (bitsX < bitsY) return((Z_int) -1); else return((Z_int) 1);
}
}
charptr BitVector_to_Hex(wordptr addr)
{
N_word bits = bits_(addr);
N_word size = size_(addr);
N_word value;
N_word count;
N_word digit;
N_word length;
charptr string;
length = bits >> 2;
if (bits AND 0x0003) length++;
string = (charptr) malloc((size_t) (length+1));
if (string == NULL) return(NULL);
string += length;
*string = (N_char) '\0';
if (size > 0)
{
*(addr+size-1) &= mask_(addr);
while ((size-- > 0) and (length > 0))
{
value = *addr++;
count = BITS >> 2;
while ((count-- > 0) and (length > 0))
{
digit = value AND 0x000F;
if (digit > 9) digit += (N_word) 'A' - 10;
else digit += (N_word) '0';
*(--string) = (N_char) digit; length--;
if ((count > 0) and (length > 0)) value >>= 4;
}
}
}
return(string);
}
ErrCode BitVector_from_Hex(wordptr addr, charptr string)
{
N_word size = size_(addr);
N_word mask = mask_(addr);
boolean ok = true;
N_word length;
N_word value;
N_word count;
int digit;
if (size > 0)
{
length = strlen((char *) string);
string += length;
while (size-- > 0)
{
value = 0;
for ( count = 0; (ok and (length > 0) and (count < BITS)); count += 4 )
{
digit = (int) *(--string); length--;
/* separate because toupper() is likely a macro! */
digit = toupper(digit);
if ((ok = (isxdigit(digit) != 0)))
{
if (digit >= (int) 'A') digit -= (int) 'A' - 10;
else digit -= (int) '0';
value |= (((N_word) digit) << count);
}
}
*addr++ = value;
}
*(--addr) &= mask;
}
if (ok) return(ErrCode_Ok);
else return(ErrCode_Pars);
}
charptr BitVector_to_Bin(wordptr addr)
{
N_word size = size_(addr);
N_word value;
N_word count;
N_word digit;
N_word length;
charptr string;
length = bits_(addr);
string = (charptr) malloc((size_t) (length+1));
if (string == NULL) return(NULL);
string += length;
*string = (N_char) '\0';
if (size > 0)
{
*(addr+size-1) &= mask_(addr);
while (size-- > 0)
{
value = *addr++;
count = BITS;
if (count > length) count = length;
while (count-- > 0)
{
digit = value AND 0x0001;
digit += (N_word) '0';
*(--string) = (N_char) digit; length--;
if (count > 0) value >>= 1;
}
}
}
return(string);
}
ErrCode BitVector_from_Bin(wordptr addr, charptr string)
{
N_word size = size_(addr);
N_word mask = mask_(addr);
boolean ok = true;
N_word length;
N_word value;
N_word count;
int digit;
if (size > 0)
{
length = strlen((char *) string);
string += length;
while (size-- > 0)
{
value = 0;
for ( count = 0; (ok and (length > 0) and (count < BITS)); count++ )
{
digit = (int) *(--string); length--;
switch (digit)
{
case (int) '0':
break;
case (int) '1':
value |= BITMASKTAB[count];
break;
default:
ok = false;
break;
}
}
*addr++ = value;
}
*(--addr) &= mask;
}
if (ok) return(ErrCode_Ok);
else return(ErrCode_Pars);
}
charptr BitVector_to_Dec(wordptr addr)
{
N_word bits = bits_(addr);
N_word length;
N_word digits;
N_word count;
N_word q;
N_word r;
boolean loop;
charptr result;
charptr string;
wordptr quot;
wordptr rest;
wordptr temp;
wordptr base;
Z_int sign;
length = (N_word) (bits / 3.3); /* digits = bits * ln(2) / ln(10) */
length += 2; /* compensate for truncating & provide space for minus sign */
result = (charptr) malloc((size_t) (length+1)); /* remember the '\0'! */
if (result == NULL) return(NULL);
string = result;
sign = BitVector_Sign(addr);
if ((bits < 4) or (sign == 0))
{
if (bits > 0) digits = *addr; else digits = (N_word) 0;
if (sign < 0) digits = ((N_word)(-((Z_word)digits))) AND mask_(addr);
*string++ = (N_char) digits + (N_char) '0';
digits = 1;
}
else
{
quot = BitVector_Create(bits,false);
if (quot == NULL)
{
BitVector_Dispose(result);
return(NULL);
}
rest = BitVector_Create(bits,false);
if (rest == NULL)
{
BitVector_Dispose(result);
BitVector_Destroy(quot);
return(NULL);
}
temp = BitVector_Create(bits,false);
if (temp == NULL)
{
BitVector_Dispose(result);
BitVector_Destroy(quot);
BitVector_Destroy(rest);
return(NULL);
}
base = BitVector_Create(bits,true);
if (base == NULL)
{
BitVector_Dispose(result);
BitVector_Destroy(quot);
BitVector_Destroy(rest);
BitVector_Destroy(temp);
return(NULL);
}
if (sign < 0) BitVector_Negate(quot,addr);
else BitVector_Copy(quot,addr);
digits = 0;
*base = EXP10;
loop = (bits >= BITS);
do
{
if (loop)
{
BitVector_Copy(temp,quot);
if (BitVector_Div_Pos(quot,temp,base,rest))
{
BitVector_Dispose(result); /* emergency exit */
BitVector_Destroy(quot);
BitVector_Destroy(rest); /* should never occur */
BitVector_Destroy(temp); /* under normal operation */
BitVector_Destroy(base);
return(NULL);
}
loop = not BitVector_is_empty(quot);
q = *rest;
}
else q = *quot;
count = LOG10;
while (((loop and (count-- > 0)) or ((not loop) and (q != 0))) and
(digits < length))
{
if (q != 0)
{
BIT_VECTOR_DIGITIZE(N_word,q,r)
}
else r = (N_word) '0';
*string++ = (N_char) r;
digits++;
}
}
while (loop and (digits < length));
BitVector_Destroy(quot);
BitVector_Destroy(rest);
BitVector_Destroy(temp);
BitVector_Destroy(base);
}
if ((sign < 0) and (digits < length))
{
*string++ = (N_char) '-';
digits++;
}
*string = (N_char) '\0';
BIT_VECTOR_reverse(result,digits);
return(result);
}
ErrCode BitVector_from_Dec(wordptr addr, charptr string)
{
ErrCode error = ErrCode_Ok;
N_word bits = bits_(addr);
N_word mask = mask_(addr);
boolean init = (bits > BITS);
boolean minus;
boolean shift;
boolean carry;
wordptr term;
wordptr base;
wordptr prod;
wordptr rank;
wordptr temp;
N_word accu;
N_word powr;
N_word count;
N_word length;
int digit;
if (bits > 0)
{
length = strlen((char *) string);
if (length == 0) return(ErrCode_Pars);
digit = (int) *string;
if ((minus = (digit == (int) '-')) or
(digit == (int) '+'))
{
string++;
if (--length == 0) return(ErrCode_Pars);
}
string += length;
term = BitVector_Create(BITS,false);
if (term == NULL)
{
return(ErrCode_Null);
}
base = BitVector_Create(BITS,false);
if (base == NULL)
{
BitVector_Destroy(term);
return(ErrCode_Null);
}
prod = BitVector_Create(bits,init);
if (prod == NULL)
{
BitVector_Destroy(term);
BitVector_Destroy(base);
return(ErrCode_Null);
}
rank = BitVector_Create(bits,init);
if (rank == NULL)
{
BitVector_Destroy(term);
BitVector_Destroy(base);
BitVector_Destroy(prod);
return(ErrCode_Null);
}
temp = BitVector_Create(bits,false);
if (temp == NULL)
{
BitVector_Destroy(term);
BitVector_Destroy(base);
BitVector_Destroy(prod);
BitVector_Destroy(rank);
return(ErrCode_Null);
}
BitVector_Empty(addr);
*base = EXP10;
shift = false;
while ((not error) and (length > 0))
{
accu = 0;
powr = 1;
count = LOG10;
while ((not error) and (length > 0) and (count-- > 0))
{
digit = (int) *(--string); length--;
/* separate because isdigit() is likely a macro! */
if (isdigit(digit) != 0)
{
accu += ((N_word) digit - (N_word) '0') * powr;
powr *= 10;
}
else error = ErrCode_Pars;
}
if (not error)
{
if (shift)
{
*term = accu;
BitVector_Copy(temp,rank);
error = BitVector_Mul_Pos(prod,temp,term,false);
}
else
{
*prod = accu;
if ((not init) and ((accu AND NOT mask) != 0)) error = ErrCode_Ovfl;
}
if (not error)
{
carry = false;
BitVector_compute(addr,addr,prod,false,&carry);
/* ignores sign change (= overflow) but not */
/* numbers too large (= carry) for resulting bit vector */
if (carry) error = ErrCode_Ovfl;
else
{
if (length > 0)
{
if (shift)
{
BitVector_Copy(temp,rank);
error = BitVector_Mul_Pos(rank,temp,base,false);
}
else
{
*rank = *base;
shift = true;
}
}
}
}
}
}
BitVector_Destroy(term);
BitVector_Destroy(base);
BitVector_Destroy(prod);
BitVector_Destroy(rank);
BitVector_Destroy(temp);
if (not error and minus)
{
BitVector_Negate(addr,addr);
if ((*(addr + size_(addr) - 1) AND mask AND NOT (mask >> 1)) == 0)
error = ErrCode_Ovfl;
}
}
return(error);
}
charptr BitVector_to_Enum(wordptr addr)
{
N_word bits = bits_(addr);
N_word sample;
N_word length;
N_word digits;
N_word factor;
N_word power;
N_word start;
N_word min;
N_word max;
charptr string;
charptr target;
boolean comma;
if (bits > 0)
{
sample = bits - 1; /* greatest possible index */
length = 2; /* account for index 0 and terminating '\0' */
digits = 1; /* account for intervening dashes and commas */
factor = 1;
power = 10;
while (sample >= (power-1))
{
length += ++digits * factor * 6; /* 9,90,900,9000,... (9*2/3 = 6) */
factor = power;
power *= 10;
}
if (sample > --factor)
{
sample -= factor;
factor = (N_word) ( sample / 3 );
factor = (factor << 1) + (sample - (factor * 3));
length += ++digits * factor;
}
}
else length = 1;
string = (charptr) malloc((size_t) length);
if (string == NULL) return(NULL);
start = 0;
comma = false;
target = string;
while ((start < bits) and BitVector_interval_scan_inc(addr,start,&min,&max))
{
start = max + 2;
if (comma) *target++ = (N_char) ',';
if (min == max)
{
target += BIT_VECTOR_int2str(target,min);
}
else
{
if (min+1 == max)
{
target += BIT_VECTOR_int2str(target,min);
*target++ = (N_char) ',';
target += BIT_VECTOR_int2str(target,max);
}
else
{
target += BIT_VECTOR_int2str(target,min);
*target++ = (N_char) '-';
target += BIT_VECTOR_int2str(target,max);
}
}
comma = true;
}
*target = (N_char) '\0';
return(string);
}
ErrCode BitVector_from_Enum(wordptr addr, charptr string)
{
ErrCode error = ErrCode_Ok;
N_word bits = bits_(addr);
N_word state = 1;
N_word token;
N_word index;
N_word start = 0; /* silence compiler warning */
if (bits > 0)
{
BitVector_Empty(addr);
while ((not error) and (state != 0))
{
token = (N_word) *string;
/* separate because isdigit() is likely a macro! */
if (isdigit((int)token) != 0)
{
string += BIT_VECTOR_str2int(string,&index);
if (index < bits) token = (N_word) '0';
else error = ErrCode_Indx;
}
else string++;
if (not error)
switch (state)
{
case 1:
switch (token)
{
case (N_word) '0':
state = 2;
break;
case (N_word) '\0':
state = 0;
break;
default:
error = ErrCode_Pars;
break;
}
break;
case 2:
switch (token)
{
case (N_word) '-':
start = index;
state = 3;
break;
case (N_word) ',':
BIT_VECTOR_SET_BIT(addr,index)
state = 5;
break;
case (N_word) '\0':
BIT_VECTOR_SET_BIT(addr,index)
state = 0;
break;
default:
error = ErrCode_Pars;
break;
}
break;
case 3:
switch (token)
{
case (N_word) '0':
if (start < index)
BitVector_Interval_Fill(addr,start,index);
else if (start == index)
BIT_VECTOR_SET_BIT(addr,index)
else error = ErrCode_Ordr;
state = 4;
break;
default:
error = ErrCode_Pars;
break;
}
break;
case 4:
switch (token)
{
case (N_word) ',':
state = 5;
break;
case (N_word) '\0':
state = 0;
break;
default:
error = ErrCode_Pars;
break;
}
break;
case 5:
switch (token)
{
case (N_word) '0':
state = 2;
break;
default:
error = ErrCode_Pars;
break;
}
break;
}
}
}
return(error);
}
void BitVector_Bit_Off(wordptr addr, N_int index) /* X = X \ {x} */
{
if (index < bits_(addr)) BIT_VECTOR_CLR_BIT(addr,index)
}
void BitVector_Bit_On(wordptr addr, N_int index) /* X = X + {x} */
{
if (index < bits_(addr)) BIT_VECTOR_SET_BIT(addr,index)
}
boolean BitVector_bit_flip(wordptr addr, N_int index) /* X=(X+{x})\(X*{x}) */
{
N_word mask;
if (index < bits_(addr)) return( BIT_VECTOR_FLP_BIT(addr,index,mask) );
else return( false );
}
boolean BitVector_bit_test(wordptr addr, N_int index) /* {x} in X ? */
{
if (index < bits_(addr)) return( BIT_VECTOR_TST_BIT(addr,index) );
else return( false );
}
void BitVector_Bit_Copy(wordptr addr, N_int index, boolean bit)
{
if (index < bits_(addr))
{
if (bit) BIT_VECTOR_SET_BIT(addr,index)
else BIT_VECTOR_CLR_BIT(addr,index)
}
}
void BitVector_LSB(wordptr addr, boolean bit)
{
if (bits_(addr) > 0)
{
if (bit) *addr |= LSB;
else *addr &= NOT LSB;
}
}
void BitVector_MSB(wordptr addr, boolean bit)
{
N_word size = size_(addr);
N_word mask = mask_(addr);
if (size-- > 0)
{
if (bit) *(addr+size) |= mask AND NOT (mask >> 1);
else *(addr+size) &= NOT mask OR (mask >> 1);
}
}
boolean BitVector_lsb_(wordptr addr)
{
if (size_(addr) > 0) return( (*addr AND LSB) != 0 );
else return( false );
}
boolean BitVector_msb_(wordptr addr)
{
N_word size = size_(addr);
N_word mask = mask_(addr);
if (size-- > 0)
return( (*(addr+size) AND (mask AND NOT (mask >> 1))) != 0 );
else
return( false );
}
boolean BitVector_rotate_left(wordptr addr)
{
N_word size = size_(addr);
N_word mask = mask_(addr);
N_word msb;
boolean carry_in;
boolean carry_out = false;
if (size > 0)
{
msb = mask AND NOT (mask >> 1);
carry_in = ((*(addr+size-1) AND msb) != 0);
while (size-- > 1)
{
carry_out = ((*addr AND MSB) != 0);
*addr <<= 1;
if (carry_in) *addr |= LSB;
carry_in = carry_out;
addr++;
}
carry_out = ((*addr AND msb) != 0);
*addr <<= 1;
if (carry_in) *addr |= LSB;
*addr &= mask;
}
return(carry_out);
}
boolean BitVector_rotate_right(wordptr addr)
{
N_word size = size_(addr);
N_word mask = mask_(addr);
N_word msb;
boolean carry_in;
boolean carry_out = false;
if (size > 0)
{
msb = mask AND NOT (mask >> 1);
carry_in = ((*addr AND LSB) != 0);
addr += size-1;
*addr &= mask;
carry_out = ((*addr AND LSB) != 0);
*addr >>= 1;
if (carry_in) *addr |= msb;
carry_in = carry_out;
addr--;
size--;
while (size-- > 0)
{
carry_out = ((*addr AND LSB) != 0);
*addr >>= 1;
if (carry_in) *addr |= MSB;
carry_in = carry_out;
addr--;
}
}
return(carry_out);
}
boolean BitVector_shift_left(wordptr addr, boolean carry_in)
{
N_word size = size_(addr);
N_word mask = mask_(addr);
N_word msb;
boolean carry_out = carry_in;
if (size > 0)
{
msb = mask AND NOT (mask >> 1);
while (size-- > 1)
{
carry_out = ((*addr AND MSB) != 0);
*addr <<= 1;
if (carry_in) *addr |= LSB;
carry_in = carry_out;
addr++;
}
carry_out = ((*addr AND msb) != 0);
*addr <<= 1;
if (carry_in) *addr |= LSB;
*addr &= mask;
}
return(carry_out);
}
boolean BitVector_shift_right(wordptr addr, boolean carry_in)
{
N_word size = size_(addr);
N_word mask = mask_(addr);
N_word msb;
boolean carry_out = carry_in;
if (size > 0)
{
msb = mask AND NOT (mask >> 1);
addr += size-1;
*addr &= mask;
carry_out = ((*addr AND LSB) != 0);
*addr >>= 1;
if (carry_in) *addr |= msb;
carry_in = carry_out;
addr--;
size--;
while (size-- > 0)
{
carry_out = ((*addr AND LSB) != 0);
*addr >>= 1;
if (carry_in) *addr |= MSB;
carry_in = carry_out;
addr--;
}
}
return(carry_out);
}
void BitVector_Move_Left(wordptr addr, N_int bits)
{
N_word count;
N_word words;
if (bits > 0)
{
count = bits AND MODMASK;
words = bits >> LOGBITS;
if (bits >= bits_(addr)) BitVector_Empty(addr);
else
{
while (count-- > 0) BitVector_shift_left(addr,0);
BitVector_Word_Insert(addr,0,words,true);
}
}
}
void BitVector_Move_Right(wordptr addr, N_int bits)
{
N_word count;
N_word words;
if (bits > 0)
{
count = bits AND MODMASK;
words = bits >> LOGBITS;
if (bits >= bits_(addr)) BitVector_Empty(addr);
else
{
while (count-- > 0) BitVector_shift_right(addr,0);
BitVector_Word_Delete(addr,0,words,true);
}
}
}
void BitVector_Insert(wordptr addr, N_int offset, N_int count, boolean clear)
{
N_word bits = bits_(addr);
N_word last;
if ((count > 0) and (offset < bits))
{
last = offset + count;
if (last < bits)
{
BitVector_Interval_Copy(addr,addr,last,offset,(bits-last));
}
else last = bits;
if (clear) BitVector_Interval_Empty(addr,offset,(last-1));
}
}
void BitVector_Delete(wordptr addr, N_int offset, N_int count, boolean clear)
{
N_word bits = bits_(addr);
N_word last;
if ((count > 0) and (offset < bits))
{
last = offset + count;
if (last < bits)
{
BitVector_Interval_Copy(addr,addr,offset,last,(bits-last));
}
else count = bits - offset;
if (clear) BitVector_Interval_Empty(addr,(bits-count),(bits-1));
}
}
boolean BitVector_increment(wordptr addr) /* X++ */
{
N_word size = size_(addr);
N_word mask = mask_(addr);
wordptr last = addr + size - 1;
boolean carry = true;
if (size > 0)
{
*last |= NOT mask;
while (carry and (size-- > 0))
{
carry = (++(*addr++) == 0);
}
*last &= mask;
}
return(carry);
}
boolean BitVector_decrement(wordptr addr) /* X-- */
{
N_word size = size_(addr);
N_word mask = mask_(addr);
wordptr last = addr + size - 1;
boolean carry = true;
if (size > 0)
{
*last &= mask;
while (carry and (size-- > 0))
{
carry = (*addr == 0);
--(*addr++);
}
*last &= mask;
}
return(carry);
}
boolean BitVector_compute(wordptr X, wordptr Y, wordptr Z, boolean minus, boolean *carry)
{
N_word size = size_(X);
N_word mask = mask_(X);
N_word vv = 0;
N_word cc;
N_word mm;
N_word yy;
N_word zz;
N_word lo;
N_word hi;
if (size > 0)
{
if (minus) cc = (*carry == 0);
else cc = (*carry != 0);
/* deal with (size-1) least significant full words first: */
while (--size > 0)
{
yy = *Y++;
if (minus) zz = (N_word) NOT ( Z ? *Z++ : 0 );
else zz = (N_word) ( Z ? *Z++ : 0 );
lo = (yy AND LSB) + (zz AND LSB) + cc;
hi = (yy >> 1) + (zz >> 1) + (lo >> 1);
cc = ((hi AND MSB) != 0);
*X++ = (hi << 1) OR (lo AND LSB);
}
/* deal with most significant word (may be used only partially): */
yy = *Y AND mask;
if (minus) zz = (N_word) NOT ( Z ? *Z : 0 );
else zz = (N_word) ( Z ? *Z : 0 );
zz &= mask;
if (mask == LSB) /* special case, only one bit used */
{
vv = cc;
lo = yy + zz + cc;
cc = (lo >> 1);
vv ^= cc;
*X = lo AND LSB;
}
else
{
if (NOT mask) /* not all bits are used, but more than one */
{
mm = (mask >> 1);
vv = (yy AND mm) + (zz AND mm) + cc;
mm = mask AND NOT mm;
lo = yy + zz + cc;
cc = (lo >> 1);
vv ^= cc;
vv &= mm;
cc &= mm;
*X = lo AND mask;
}
else /* other special case, all bits are used */
{
mm = NOT MSB;
lo = (yy AND mm) + (zz AND mm) + cc;
vv = lo AND MSB;
hi = ((yy AND MSB) >> 1) + ((zz AND MSB) >> 1) + (vv >> 1);
cc = hi AND MSB;
vv ^= cc;
*X = (hi << 1) OR (lo AND mm);
}
}
if (minus) *carry = (cc == 0);
else *carry = (cc != 0);
}
return(vv != 0);
}
boolean BitVector_add(wordptr X, wordptr Y, wordptr Z, boolean *carry)
{
return(BitVector_compute(X,Y,Z,false,carry));
}
boolean BitVector_sub(wordptr X, wordptr Y, wordptr Z, boolean *carry)
{
return(BitVector_compute(X,Y,Z,true,carry));
}
boolean BitVector_inc(wordptr X, wordptr Y)
{
boolean carry = true;
return(BitVector_compute(X,Y,NULL,false,&carry));
}
boolean BitVector_dec(wordptr X, wordptr Y)
{
boolean carry = true;
return(BitVector_compute(X,Y,NULL,true,&carry));
}
void BitVector_Negate(wordptr X, wordptr Y)
{
N_word size = size_(X);
N_word mask = mask_(X);
boolean carry = true;
if (size > 0)
{
while (size-- > 0)
{
*X = NOT *Y++;
if (carry)
{
carry = (++(*X) == 0);
}
X++;
}
*(--X) &= mask;
}
}
void BitVector_Absolute(wordptr X, wordptr Y)
{
N_word size = size_(Y);
N_word mask = mask_(Y);
if (size > 0)
{
if (*(Y+size-1) AND (mask AND NOT (mask >> 1))) BitVector_Negate(X,Y);
else BitVector_Copy(X,Y);
}
}
Z_int BitVector_Sign(wordptr addr)
{
N_word size = size_(addr);
N_word mask = mask_(addr);
wordptr last = addr + size - 1;
boolean r = true;
if (size > 0)
{
*last &= mask;
while (r and (size-- > 0)) r = ( *addr++ == 0 );
}
if (r) return((Z_int) 0);
else
{
if (*last AND (mask AND NOT (mask >> 1))) return((Z_int) -1);
else return((Z_int) 1);
}
}
ErrCode BitVector_Mul_Pos(wordptr X, wordptr Y, wordptr Z, boolean strict)
{
N_word mask;
N_word limit;
N_word count;
Z_long last;
wordptr sign;
boolean carry;
boolean overflow;
boolean ok = true;
/*
Requirements:
- X, Y and Z must be distinct
- X and Y must have equal sizes (whereas Z may be any size!)
- Z should always contain the SMALLER of the two factors Y and Z
Constraints:
- The contents of Y (and of X, of course) are destroyed
(only Z is preserved!)
*/
if ((X == Y) or (X == Z) or (Y == Z)) return(ErrCode_Same);
if (bits_(X) != bits_(Y)) return(ErrCode_Size);
BitVector_Empty(X);
if (BitVector_is_empty(Y)) return(ErrCode_Ok); /* exit also taken if bits_(Y)==0 */
if ((last = Set_Max(Z)) < 0L) return(ErrCode_Ok);
limit = (N_word) last;
sign = Y + size_(Y) - 1;
mask = mask_(Y);
*sign &= mask;
mask &= NOT (mask >> 1);
for ( count = 0; (ok and (count <= limit)); count++ )
{
if ( BIT_VECTOR_TST_BIT(Z,count) )
{
carry = false;
overflow = BitVector_compute(X,X,Y,false,&carry);
if (strict) ok = not (carry or overflow);
else ok = not carry;
}
if (ok and (count < limit))
{
carry = BitVector_shift_left(Y,0);
if (strict)
{
overflow = ((*sign AND mask) != 0);
ok = not (carry or overflow);
}
else ok = not carry;
}
}
if (ok) return(ErrCode_Ok); else return(ErrCode_Ovfl);
}
ErrCode BitVector_Multiply(wordptr X, wordptr Y, wordptr Z)
{
ErrCode error = ErrCode_Ok;
N_word bit_x = bits_(X);
N_word bit_y = bits_(Y);
N_word bit_z = bits_(Z);
N_word size;
N_word mask;
N_word msb;
wordptr ptr_y;
wordptr ptr_z;
boolean sgn_x;
boolean sgn_y;
boolean sgn_z;
boolean zero;
wordptr A;
wordptr B;
/*
Requirements:
- Y and Z must have equal sizes
- X must have at least the same size as Y and Z but may be larger (!)
Features:
- The contents of Y and Z are preserved
- X may be identical with Y or Z (or both!)
(in-place multiplication is possible!)
*/
if ((bit_y != bit_z) or (bit_x < bit_y)) return(ErrCode_Size);
if (BitVector_is_empty(Y) or BitVector_is_empty(Z))
{
BitVector_Empty(X);
}
else
{
A = BitVector_Create(bit_y,false);
if (A == NULL) return(ErrCode_Null);
B = BitVector_Create(bit_z,false);
if (B == NULL) { BitVector_Destroy(A); return(ErrCode_Null); }
size = size_(Y);
mask = mask_(Y);
msb = (mask AND NOT (mask >> 1));
sgn_y = (((*(Y+size-1) &= mask) AND msb) != 0);
sgn_z = (((*(Z+size-1) &= mask) AND msb) != 0);
sgn_x = sgn_y XOR sgn_z;
if (sgn_y) BitVector_Negate(A,Y); else BitVector_Copy(A,Y);
if (sgn_z) BitVector_Negate(B,Z); else BitVector_Copy(B,Z);
ptr_y = A + size;
ptr_z = B + size;
zero = true;
while (zero and (size-- > 0))
{
zero &= (*(--ptr_y) == 0);
zero &= (*(--ptr_z) == 0);
}
if (*ptr_y > *ptr_z)
{
if (bit_x > bit_y)
{
A = BitVector_Resize(A,bit_x);
if (A == NULL) { BitVector_Destroy(B); return(ErrCode_Null); }
}
error = BitVector_Mul_Pos(X,A,B,true);
}
else
{
if (bit_x > bit_z)
{
B = BitVector_Resize(B,bit_x);
if (B == NULL) { BitVector_Destroy(A); return(ErrCode_Null); }
}
error = BitVector_Mul_Pos(X,B,A,true);
}
if ((not error) and sgn_x) BitVector_Negate(X,X);
BitVector_Destroy(A);
BitVector_Destroy(B);
}
return(error);
}
ErrCode BitVector_Div_Pos(wordptr Q, wordptr X, wordptr Y, wordptr R)
{
N_word bits = bits_(Q);
N_word mask;
wordptr addr;
Z_long last;
boolean flag;
boolean copy = false; /* flags whether valid rest is in R (0) or X (1) */
/*
Requirements:
- All bit vectors must have equal sizes
- Q, X, Y and R must all be distinct bit vectors
- Y must be non-zero (of course!)
Constraints:
- The contents of X (and Q and R, of course) are destroyed
(only Y is preserved!)
*/
if ((bits != bits_(X)) or (bits != bits_(Y)) or (bits != bits_(R)))
return(ErrCode_Size);
if ((Q == X) or (Q == Y) or (Q == R) or (X == Y) or (X == R) or (Y == R))
return(ErrCode_Same);
if (BitVector_is_empty(Y))
return(ErrCode_Zero);
BitVector_Empty(R);
BitVector_Copy(Q,X);
if ((last = Set_Max(Q)) < 0L) return(ErrCode_Ok);
bits = (N_word) ++last;
while (bits-- > 0)
{
addr = Q + (bits >> LOGBITS);
mask = BITMASKTAB[bits AND MODMASK];
flag = ((*addr AND mask) != 0);
if (copy)
{
BitVector_shift_left(X,flag);
flag = false;
BitVector_compute(R,X,Y,true,&flag);
}
else
{
BitVector_shift_left(R,flag);
flag = false;
BitVector_compute(X,R,Y,true,&flag);
}
if (flag) *addr &= NOT mask;
else
{
*addr |= mask;
copy = not copy;
}
}
if (copy) BitVector_Copy(R,X);
return(ErrCode_Ok);
}
ErrCode BitVector_Divide(wordptr Q, wordptr X, wordptr Y, wordptr R)
{
ErrCode error = ErrCode_Ok;
N_word bits = bits_(Q);
N_word size = size_(Q);
N_word mask = mask_(Q);
N_word msb = (mask AND NOT (mask >> 1));
boolean sgn_q;
boolean sgn_x;
boolean sgn_y;
wordptr A;
wordptr B;
/*
Requirements:
- All bit vectors must have equal sizes
- Q and R must be two distinct bit vectors
- Y must be non-zero (of course!)
Features:
- The contents of X and Y are preserved
- Q may be identical with X or Y (or both)
(in-place division is possible!)
- R may be identical with X or Y (or both)
(but not identical with Q!)
*/
if ((bits != bits_(X)) or (bits != bits_(Y)) or (bits != bits_(R)))
return(ErrCode_Size);
if (Q == R)
return(ErrCode_Same);
if (BitVector_is_empty(Y))
return(ErrCode_Zero);
if (BitVector_is_empty(X))
{
BitVector_Empty(Q);
BitVector_Empty(R);
}
else
{
A = BitVector_Create(bits,false);
if (A == NULL) return(ErrCode_Null);
B = BitVector_Create(bits,false);
if (B == NULL) { BitVector_Destroy(A); return(ErrCode_Null); }
size--;
sgn_x = (((*(X+size) &= mask) AND msb) != 0);
sgn_y = (((*(Y+size) &= mask) AND msb) != 0);
sgn_q = sgn_x XOR sgn_y;
if (sgn_x) BitVector_Negate(A,X); else BitVector_Copy(A,X);
if (sgn_y) BitVector_Negate(B,Y); else BitVector_Copy(B,Y);
if (not (error = BitVector_Div_Pos(Q,A,B,R)))
{
if (sgn_q) BitVector_Negate(Q,Q);
if (sgn_x) BitVector_Negate(R,R);
}
BitVector_Destroy(A);
BitVector_Destroy(B);
}
return(error);
}
ErrCode BitVector_GCD(wordptr X, wordptr Y, wordptr Z)
{
ErrCode error = ErrCode_Ok;
N_word bits = bits_(X);
N_word size = size_(X);
N_word mask = mask_(X);
N_word msb = (mask AND NOT (mask >> 1));
boolean sgn_a;
boolean sgn_b;
boolean sgn_r;
wordptr Q;
wordptr R;
wordptr A;
wordptr B;
wordptr T;
/*
Requirements:
- All bit vectors must have equal sizes
Features:
- The contents of Y and Z are preserved
- X may be identical with Y or Z (or both)
(in-place is possible!)
- GCD(0,z) == GCD(z,0) == z
- negative values are handled correctly
*/
if ((bits != bits_(Y)) or (bits != bits_(Z))) return(ErrCode_Size);
if (BitVector_is_empty(Y))
{
if (X != Z) BitVector_Copy(X,Z);
return(ErrCode_Ok);
}
if (BitVector_is_empty(Z))
{
if (X != Y) BitVector_Copy(X,Y);
return(ErrCode_Ok);
}
Q = BitVector_Create(bits,false);
if (Q == NULL)
{
return(ErrCode_Null);
}
R = BitVector_Create(bits,false);
if (R == NULL)
{
BitVector_Destroy(Q);
return(ErrCode_Null);
}
A = BitVector_Create(bits,false);
if (A == NULL)
{
BitVector_Destroy(Q);
BitVector_Destroy(R);
return(ErrCode_Null);
}
B = BitVector_Create(bits,false);
if (B == NULL)
{
BitVector_Destroy(Q);
BitVector_Destroy(R);
BitVector_Destroy(A);
return(ErrCode_Null);
}
size--;
sgn_a = (((*(Y+size) &= mask) AND msb) != 0);
sgn_b = (((*(Z+size) &= mask) AND msb) != 0);
if (sgn_a) BitVector_Negate(A,Y); else BitVector_Copy(A,Y);
if (sgn_b) BitVector_Negate(B,Z); else BitVector_Copy(B,Z);
while (not error)
{
if (not (error = BitVector_Div_Pos(Q,A,B,R)))
{
if (BitVector_is_empty(R)) break;
T = A; sgn_r = sgn_a;
A = B; sgn_a = sgn_b;
B = R; sgn_b = sgn_r;
R = T;
}
}
if (not error)
{
if (sgn_b) BitVector_Negate(X,B); else BitVector_Copy(X,B);
}
BitVector_Destroy(Q);
BitVector_Destroy(R);
BitVector_Destroy(A);
BitVector_Destroy(B);
return(error);
}
ErrCode BitVector_GCD2(wordptr U, wordptr V, wordptr W, wordptr X, wordptr Y)
{
ErrCode error = ErrCode_Ok;
N_word bits = bits_(U);
N_word size = size_(U);
N_word mask = mask_(U);
N_word msb = (mask AND NOT (mask >> 1));
boolean minus;
boolean carry;
boolean sgn_q;
boolean sgn_r;
boolean sgn_a;
boolean sgn_b;
boolean sgn_x;
boolean sgn_y;
listptr L;
wordptr Q;
wordptr R;
wordptr A;
wordptr B;
wordptr T;
wordptr X1;
wordptr X2;
wordptr X3;
wordptr Y1;
wordptr Y2;
wordptr Y3;
wordptr Z;
/*
Requirements:
- All bit vectors must have equal sizes
- U, V, and W must all be distinct bit vectors
Features:
- The contents of X and Y are preserved
- U, V and W may be identical with X or Y (or both,
provided that U, V and W are mutually distinct)
(i.e., in-place is possible!)
- GCD(0,z) == GCD(z,0) == z
- negative values are handled correctly
*/
if ((bits != bits_(V)) or
(bits != bits_(W)) or
(bits != bits_(X)) or
(bits != bits_(Y)))
{
return(ErrCode_Size);
}
if ((U == V) or (U == W) or (V == W))
{
return(ErrCode_Same);
}
if (BitVector_is_empty(X))
{
if (U != Y) BitVector_Copy(U,Y);
BitVector_Empty(V);
BitVector_Empty(W);
*W = 1;
return(ErrCode_Ok);
}
if (BitVector_is_empty(Y))
{
if (U != X) BitVector_Copy(U,X);
BitVector_Empty(V);
BitVector_Empty(W);
*V = 1;
return(ErrCode_Ok);
}
if ((L = BitVector_Create_List(bits,false,11)) == NULL)
{
return(ErrCode_Null);
}
Q = L[0];
R = L[1];
A = L[2];
B = L[3];
X1 = L[4];
X2 = L[5];
X3 = L[6];
Y1 = L[7];
Y2 = L[8];
Y3 = L[9];
Z = L[10];
size--;
sgn_a = (((*(X+size) &= mask) AND msb) != 0);
sgn_b = (((*(Y+size) &= mask) AND msb) != 0);
if (sgn_a) BitVector_Negate(A,X); else BitVector_Copy(A,X);
if (sgn_b) BitVector_Negate(B,Y); else BitVector_Copy(B,Y);
BitVector_Empty(X1);
BitVector_Empty(X2);
*X1 = 1;
BitVector_Empty(Y1);
BitVector_Empty(Y2);
*Y2 = 1;
sgn_x = false;
sgn_y = false;
while (not error)
{
if ((error = BitVector_Div_Pos(Q,A,B,R)))
{
break;
}
if (BitVector_is_empty(R))
{
break;
}
sgn_q = sgn_a XOR sgn_b;
if (sgn_x) BitVector_Negate(Z,X2); else BitVector_Copy(Z,X2);
if ((error = BitVector_Mul_Pos(X3,Z,Q,true)))
{
break;
}
minus = not (sgn_x XOR sgn_q);
carry = 0;
if (BitVector_compute(X3,X1,X3,minus,&carry))
{
error = ErrCode_Ovfl;
break;
}
sgn_x = (((*(X3+size) &= mask) AND msb) != 0);
if (sgn_y) BitVector_Negate(Z,Y2); else BitVector_Copy(Z,Y2);
if ((error = BitVector_Mul_Pos(Y3,Z,Q,true)))
{
break;
}
minus = not (sgn_y XOR sgn_q);
carry = 0;
if (BitVector_compute(Y3,Y1,Y3,minus,&carry))
{
error = ErrCode_Ovfl;
break;
}
sgn_y = (((*(Y3+size) &= mask) AND msb) != 0);
T = A; sgn_r = sgn_a;
A = B; sgn_a = sgn_b;
B = R; sgn_b = sgn_r;
R = T;
T = X1;
X1 = X2;
X2 = X3;
X3 = T;
T = Y1;
Y1 = Y2;
Y2 = Y3;
Y3 = T;
}
if (not error)
{
if (sgn_b) BitVector_Negate(U,B); else BitVector_Copy(U,B);
BitVector_Copy(V,X2);
BitVector_Copy(W,Y2);
}
BitVector_Destroy_List(L,11);
return(error);
}
ErrCode BitVector_Power(wordptr X, wordptr Y, wordptr Z)
{
ErrCode error = ErrCode_Ok;
N_word bits = bits_(X);
boolean first = true;
Z_long last;
N_word limit;
N_word count;
wordptr T;
/*
Requirements:
- X must have at least the same size as Y but may be larger (!)
- X may not be identical with Z
- Z must be positive
Features:
- The contents of Y and Z are preserved
*/
if (X == Z) return(ErrCode_Same);
if (bits < bits_(Y)) return(ErrCode_Size);
if (BitVector_msb_(Z)) return(ErrCode_Expo);
if ((last = Set_Max(Z)) < 0L)
{
if (bits < 2) return(ErrCode_Ovfl);
BitVector_Empty(X);
*X |= LSB;
return(ErrCode_Ok); /* anything ^ 0 == 1 */
}
if (BitVector_is_empty(Y))
{
if (X != Y) BitVector_Empty(X);
return(ErrCode_Ok); /* 0 ^ anything not zero == 0 */
}
T = BitVector_Create(bits,false);
if (T == NULL) return(ErrCode_Null);
limit = (N_word) last;
for ( count = 0; ((!error) and (count <= limit)); count++ )
{
if ( BIT_VECTOR_TST_BIT(Z,count) )
{
if (first)
{
first = false;
if (count) { BitVector_Copy(X,T); }
else { if (X != Y) BitVector_Copy(X,Y); }
}
else error = BitVector_Multiply(X,T,X); /* order important because T > X */
}
if ((!error) and (count < limit))
{
if (count) error = BitVector_Multiply(T,T,T);
else error = BitVector_Multiply(T,Y,Y);
}
}
BitVector_Destroy(T);
return(error);
}
void BitVector_Block_Store(wordptr addr, charptr buffer, N_int length)
{
N_word size = size_(addr);
N_word mask = mask_(addr);
N_word value;
N_word count;
/* provide translation for independence of endian-ness: */
if (size > 0)
{
while (size-- > 0)
{
value = 0;
for ( count = 0; (length > 0) and (count < BITS); count += 8 )
{
value |= (((N_word) *buffer++) << count); length--;
}
*addr++ = value;
}
*(--addr) &= mask;
}
}
charptr BitVector_Block_Read(wordptr addr, N_intptr length)
{
N_word size = size_(addr);
N_word value;
N_word count;
charptr buffer;
charptr target;
/* provide translation for independence of endian-ness: */
*length = size << FACTOR;
buffer = (charptr) malloc((size_t) ((*length)+1));
if (buffer == NULL) return(NULL);
target = buffer;
if (size > 0)
{
*(addr+size-1) &= mask_(addr);
while (size-- > 0)
{
value = *addr++;
count = BITS >> 3;
while (count-- > 0)
{
*target++ = (N_char) (value AND 0x00FF);
if (count > 0) value >>= 8;
}
}
}
*target = (N_char) '\0';
return(buffer);
}
void BitVector_Word_Store(wordptr addr, N_int offset, N_int value)
{
N_word size = size_(addr);
if (size > 0)
{
if (offset < size) *(addr+offset) = value;
*(addr+size-1) &= mask_(addr);
}
}
N_int BitVector_Word_Read(wordptr addr, N_int offset)
{
N_word size = size_(addr);
if (size > 0)
{
*(addr+size-1) &= mask_(addr);
if (offset < size) return( *(addr+offset) );
}
return( (N_int) 0 );
}
void BitVector_Word_Insert(wordptr addr, N_int offset, N_int count,
boolean clear)
{
N_word size = size_(addr);
N_word mask = mask_(addr);
wordptr last = addr+size-1;
if (size > 0)
{
*last &= mask;
if (offset > size) offset = size;
BIT_VECTOR_ins_words(addr+offset,size-offset,count,clear);
*last &= mask;
}
}
void BitVector_Word_Delete(wordptr addr, N_int offset, N_int count,
boolean clear)
{
N_word size = size_(addr);
N_word mask = mask_(addr);
wordptr last = addr+size-1;
if (size > 0)
{
*last &= mask;
if (offset > size) offset = size;
BIT_VECTOR_del_words(addr+offset,size-offset,count,clear);
*last &= mask;
}
}
void BitVector_Chunk_Store(wordptr addr, N_int chunksize, N_int offset,
N_long value)
{
N_word bits = bits_(addr);
N_word mask;
N_word temp;
if ((chunksize > 0) and (offset < bits))
{
if (chunksize > LONGBITS) chunksize = LONGBITS;
if ((offset + chunksize) > bits) chunksize = bits - offset;
addr += offset >> LOGBITS;
offset &= MODMASK;
while (chunksize > 0)
{
mask = (N_word) (~0L << offset);
bits = offset + chunksize;
if (bits < BITS)
{
mask &= (N_word) ~(~0L << bits);
bits = chunksize;
}
else bits = BITS - offset;
temp = (N_word) (value << offset);
temp &= mask;
*addr &= NOT mask;
*addr++ |= temp;
value >>= bits;
chunksize -= bits;
offset = 0;
}
}
}
N_long BitVector_Chunk_Read(wordptr addr, N_int chunksize, N_int offset)
{
N_word bits = bits_(addr);
N_word chunkbits = 0;
N_long value = 0L;
N_long temp;
N_word mask;
if ((chunksize > 0) and (offset < bits))
{
if (chunksize > LONGBITS) chunksize = LONGBITS;
if ((offset + chunksize) > bits) chunksize = bits - offset;
addr += offset >> LOGBITS;
offset &= MODMASK;
while (chunksize > 0)
{
bits = offset + chunksize;
if (bits < BITS)
{
mask = (N_word) ~(~0L << bits);
bits = chunksize;
}
else
{
mask = (N_word) ~0L;
bits = BITS - offset;
}
temp = (N_long) ((*addr++ AND mask) >> offset);
value |= temp << chunkbits;
chunkbits += bits;
chunksize -= bits;
offset = 0;
}
}
return(value);
}
/*******************/
/* set operations: */
/*******************/
void Set_Union(wordptr X, wordptr Y, wordptr Z) /* X = Y + Z */
{
N_word bits = bits_(X);
N_word size = size_(X);
N_word mask = mask_(X);
if ((size > 0) and (bits == bits_(Y)) and (bits == bits_(Z)))
{
while (size-- > 0) *X++ = *Y++ OR *Z++;
*(--X) &= mask;
}
}
void Set_Intersection(wordptr X, wordptr Y, wordptr Z) /* X = Y * Z */
{
N_word bits = bits_(X);
N_word size = size_(X);
N_word mask = mask_(X);
if ((size > 0) and (bits == bits_(Y)) and (bits == bits_(Z)))
{
while (size-- > 0) *X++ = *Y++ AND *Z++;
*(--X) &= mask;
}
}
void Set_Difference(wordptr X, wordptr Y, wordptr Z) /* X = Y \ Z */
{
N_word bits = bits_(X);
N_word size = size_(X);
N_word mask = mask_(X);
if ((size > 0) and (bits == bits_(Y)) and (bits == bits_(Z)))
{
while (size-- > 0) *X++ = *Y++ AND NOT *Z++;
*(--X) &= mask;
}
}
void Set_ExclusiveOr(wordptr X, wordptr Y, wordptr Z) /* X=(Y+Z)\(Y*Z) */
{
N_word bits = bits_(X);
N_word size = size_(X);
N_word mask = mask_(X);
if ((size > 0) and (bits == bits_(Y)) and (bits == bits_(Z)))
{
while (size-- > 0) *X++ = *Y++ XOR *Z++;
*(--X) &= mask;
}
}
void Set_Complement(wordptr X, wordptr Y) /* X = ~Y */
{
N_word size = size_(X);
N_word mask = mask_(X);
if ((size > 0) and (bits_(X) == bits_(Y)))
{
while (size-- > 0) *X++ = NOT *Y++;
*(--X) &= mask;
}
}
/******************/
/* set functions: */
/******************/
boolean Set_subset(wordptr X, wordptr Y) /* X subset Y ? */
{
N_word size = size_(X);
boolean r = false;
if ((size > 0) and (bits_(X) == bits_(Y)))
{
r = true;
while (r and (size-- > 0)) r = ((*X++ AND NOT *Y++) == 0);
}
return(r);
}
N_int Set_Norm(wordptr addr) /* = | X | */
{
byteptr byte;
N_word bytes;
N_int n;
byte = (byteptr) addr;
bytes = size_(addr) << FACTOR;
n = 0;
while (bytes-- > 0)
{
n += BitVector_BYTENORM[*byte++];
}
return(n);
}
N_int Set_Norm2(wordptr addr) /* = | X | */
{
N_word size = size_(addr);
N_word w0,w1;
N_int n,k;
n = 0;
while (size-- > 0)
{
k = 0;
w1 = NOT (w0 = *addr++);
while (w0 and w1)
{
w0 &= w0 - 1;
w1 &= w1 - 1;
k++;
}
if (w0 == 0) n += k;
else n += BITS - k;
}
return(n);
}
N_int Set_Norm3(wordptr addr) /* = | X | */
{
N_word size = size_(addr);
N_int count = 0;
N_word c;
while (size-- > 0)
{
c = *addr++;
while (c)
{
c &= c - 1;
count++;
}
}
return(count);
}
Z_long Set_Min(wordptr addr) /* = min(X) */
{
boolean empty = true;
N_word size = size_(addr);
N_word i = 0;
N_word c = 0; /* silence compiler warning */
while (empty and (size-- > 0))
{
if ((c = *addr++)) empty = false; else i++;
}
if (empty) return((Z_long) LONG_MAX); /* plus infinity */
i <<= LOGBITS;
while (not (c AND LSB))
{
c >>= 1;
i++;
}
return((Z_long) i);
}
Z_long Set_Max(wordptr addr) /* = max(X) */
{
boolean empty = true;
N_word size = size_(addr);
N_word i = size;
N_word c = 0; /* silence compiler warning */
addr += size-1;
while (empty and (size-- > 0))
{
if ((c = *addr--)) empty = false; else i--;
}
if (empty) return((Z_long) LONG_MIN); /* minus infinity */
i <<= LOGBITS;
while (not (c AND MSB))
{
c <<= 1;
i--;
}
return((Z_long) --i);
}
/**********************************/
/* matrix-of-booleans operations: */
/**********************************/
void Matrix_Multiplication(wordptr X, N_int rowsX, N_int colsX,
wordptr Y, N_int rowsY, N_int colsY,
wordptr Z, N_int rowsZ, N_int colsZ)
{
N_word i;
N_word j;
N_word k;
N_word indxX;
N_word indxY;
N_word indxZ;
N_word termX;
N_word termY;
N_word sum;
if ((colsY == rowsZ) and (rowsX == rowsY) and (colsX == colsZ) and
(bits_(X) == rowsX*colsX) and
(bits_(Y) == rowsY*colsY) and
(bits_(Z) == rowsZ*colsZ))
{
for ( i = 0; i < rowsY; i++ )
{
termX = i * colsX;
termY = i * colsY;
for ( j = 0; j < colsZ; j++ )
{
indxX = termX + j;
sum = 0;
for ( k = 0; k < colsY; k++ )
{
indxY = termY + k;
indxZ = k * colsZ + j;
if ( BIT_VECTOR_TST_BIT(Y,indxY) &&
BIT_VECTOR_TST_BIT(Z,indxZ) ) sum ^= 1;
}
if (sum) BIT_VECTOR_SET_BIT(X,indxX)
else BIT_VECTOR_CLR_BIT(X,indxX)
}
}
}
}
void Matrix_Product(wordptr X, N_int rowsX, N_int colsX,
wordptr Y, N_int rowsY, N_int colsY,
wordptr Z, N_int rowsZ, N_int colsZ)
{
N_word i;
N_word j;
N_word k;
N_word indxX;
N_word indxY;
N_word indxZ;
N_word termX;
N_word termY;
N_word sum;
if ((colsY == rowsZ) and (rowsX == rowsY) and (colsX == colsZ) and
(bits_(X) == rowsX*colsX) and
(bits_(Y) == rowsY*colsY) and
(bits_(Z) == rowsZ*colsZ))
{
for ( i = 0; i < rowsY; i++ )
{
termX = i * colsX;
termY = i * colsY;
for ( j = 0; j < colsZ; j++ )
{
indxX = termX + j;
sum = 0;
for ( k = 0; k < colsY; k++ )
{
indxY = termY + k;
indxZ = k * colsZ + j;
if ( BIT_VECTOR_TST_BIT(Y,indxY) &&
BIT_VECTOR_TST_BIT(Z,indxZ) ) sum |= 1;
}
if (sum) BIT_VECTOR_SET_BIT(X,indxX)
else BIT_VECTOR_CLR_BIT(X,indxX)
}
}
}
}
void Matrix_Closure(wordptr addr, N_int rows, N_int cols)
{
N_word i;
N_word j;
N_word k;
N_word ii;
N_word ij;
N_word ik;
N_word kj;
N_word termi;
N_word termk;
if ((rows == cols) and (bits_(addr) == rows*cols))
{
for ( i = 0; i < rows; i++ )
{
ii = i * cols + i;
BIT_VECTOR_SET_BIT(addr,ii)
}
for ( k = 0; k < rows; k++ )
{
termk = k * cols;
for ( i = 0; i < rows; i++ )
{
termi = i * cols;
ik = termi + k;
for ( j = 0; j < rows; j++ )
{
ij = termi + j;
kj = termk + j;
if ( BIT_VECTOR_TST_BIT(addr,ik) &&
BIT_VECTOR_TST_BIT(addr,kj) )
BIT_VECTOR_SET_BIT(addr,ij)
}
}
}
}
}
void Matrix_Transpose(wordptr X, N_int rowsX, N_int colsX,
wordptr Y, N_int rowsY, N_int colsY)
{
N_word i;
N_word j;
N_word ii;
N_word ij;
N_word ji;
N_word addii;
N_word addij;
N_word addji;
N_word bitii;
N_word bitij;
N_word bitji;
N_word termi;
N_word termj;
boolean swap;
/* BEWARE that "in-place" is ONLY possible if the matrix is quadratic!! */
if ((rowsX == colsY) and (colsX == rowsY) and
(bits_(X) == rowsX*colsX) and
(bits_(Y) == rowsY*colsY))
{
if (rowsY == colsY) /* in-place is possible! */
{
for ( i = 0; i < rowsY; i++ )
{
termi = i * colsY;
for ( j = 0; j < i; j++ )
{
termj = j * colsX;
ij = termi + j;
ji = termj + i;
addij = ij >> LOGBITS;
addji = ji >> LOGBITS;
bitij = BITMASKTAB[ij AND MODMASK];
bitji = BITMASKTAB[ji AND MODMASK];
swap = ((*(Y+addij) AND bitij) != 0);
if ((*(Y+addji) AND bitji) != 0)
*(X+addij) |= bitij;
else
*(X+addij) &= NOT bitij;
if (swap)
*(X+addji) |= bitji;
else
*(X+addji) &= NOT bitji;
}
ii = termi + i;
addii = ii >> LOGBITS;
bitii = BITMASKTAB[ii AND MODMASK];
if ((*(Y+addii) AND bitii) != 0)
*(X+addii) |= bitii;
else
*(X+addii) &= NOT bitii;
}
}
else /* rowsX != colsX, in-place is NOT possible! */
{
for ( i = 0; i < rowsY; i++ )
{
termi = i * colsY;
for ( j = 0; j < colsY; j++ )
{
termj = j * colsX;
ij = termi + j;
ji = termj + i;
addij = ij >> LOGBITS;
addji = ji >> LOGBITS;
bitij = BITMASKTAB[ij AND MODMASK];
bitji = BITMASKTAB[ji AND MODMASK];
if ((*(Y+addij) AND bitij) != 0)
*(X+addji) |= bitji;
else
*(X+addji) &= NOT bitji;
}
}
}
}
}
/*****************************************************************************/
/* VERSION: 6.4 */
/*****************************************************************************/
/* VERSION HISTORY: */
/*****************************************************************************/
/* */
/* Version 6.4 03.10.04 Added C++ comp. directives. Improved "Norm()". */
/* Version 6.3 28.09.02 Added "Create_List()" and "GCD2()". */
/* Version 6.2 15.09.02 Overhauled error handling. Fixed "GCD()". */
/* Version 6.1 08.10.01 Make VMS linker happy: _lsb,_msb => _lsb_,_msb_ */
/* Version 6.0 08.10.00 Corrected overflow handling. */
/* Version 5.8 14.07.00 Added "Power()". Changed "Copy()". */
/* Version 5.7 19.05.99 Quickened "Div_Pos()". Added "Product()". */
/* Version 5.6 02.11.98 Leading zeros eliminated in "to_Hex()". */
/* Version 5.5 21.09.98 Fixed bug of uninitialized "error" in Multiply. */
/* Version 5.4 07.09.98 Fixed bug of uninitialized "error" in Divide. */
/* Version 5.3 12.05.98 Improved Norm. Completed history. */
/* Version 5.2 31.03.98 Improved Norm. */
/* Version 5.1 09.03.98 No changes. */
/* Version 5.0 01.03.98 Major additions and rewrite. */
/* Version 4.2 16.07.97 Added is_empty, is_full. */
/* Version 4.1 30.06.97 Added word-ins/del, move-left/right, inc/dec. */
/* Version 4.0 23.04.97 Rewrite. Added bit shift and bool. matrix ops. */
/* Version 3.2 04.02.97 Added interval methods. */
/* Version 3.1 21.01.97 Fixed bug on 64 bit machines. */
/* Version 3.0 12.01.97 Added flip. */
/* Version 2.0 14.12.96 Efficiency and consistency improvements. */
/* Version 1.1 08.01.96 Added Resize and ExclusiveOr. */
/* Version 1.0 14.12.95 First version under UNIX (with Perl module). */
/* Version 0.9 01.11.93 First version of C library under MS-DOS. */
/* Version 0.1 ??.??.89 First version in Turbo Pascal under CP/M. */
/* */
/*****************************************************************************/
/* AUTHOR: */
/*****************************************************************************/
/* */
/* Steffen Beyer */
/* mailto:sb@engelschall.com */
/* http://www.engelschall.com/u/sb/download/ */
/* */
/*****************************************************************************/
/* COPYRIGHT: */
/*****************************************************************************/
/* */
/* Copyright (c) 1995 - 2004 by Steffen Beyer. */
/* All rights reserved. */
/* */
/*****************************************************************************/
/* LICENSE: */
/*****************************************************************************/
/* */
/* This library is free software; you can redistribute it and/or */
/* modify it under the terms of the GNU Library General Public */
/* License as published by the Free Software Foundation; either */
/* version 2 of the License, or (at your option) any later version. */
/* */
/* This library is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
/* Library General Public License for more details. */
/* */
/* You should have received a copy of the GNU Library General Public */
/* License along with this library; if not, write to the */
/* Free Software Foundation, Inc., */
/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* */
/* or download a copy from ftp://ftp.gnu.org/pub/gnu/COPYING.LIB-2.0 */
/* */
/*****************************************************************************/
#endif
psad-7c4a910/deps/Bit-Vector/BitVector.h 0000664 0000000 0000000 00000047541 12071203757 0017775 0 ustar 00root root 0000000 0000000 #ifndef MODULE_BIT_VECTOR
#define MODULE_BIT_VECTOR
#ifdef __cplusplus
extern "C"
{
#endif
/*****************************************************************************/
/* MODULE NAME: BitVector.h MODULE TYPE: (adt) */
/*****************************************************************************/
/* MODULE IMPORTS: */
/*****************************************************************************/
#include /* MODULE TYPE: (sys) */
#include /* MODULE TYPE: (sys) */
#include /* MODULE TYPE: (sys) */
#include /* MODULE TYPE: (sys) */
#include "ToolBox.h" /* MODULE TYPE: (dat) */
/*****************************************************************************/
/* MODULE INTERFACE: */
/*****************************************************************************/
typedef enum
{
ErrCode_Ok = 0, /* everything went allright */
ErrCode_Type, /* types word and size_t have incompatible sizes */
ErrCode_Bits, /* bits of word and sizeof(word) are inconsistent */
ErrCode_Word, /* size of word is less than 16 bits */
ErrCode_Long, /* size of word is greater than size of long */
ErrCode_Powr, /* number of bits of word is not a power of two */
ErrCode_Loga, /* error in calculation of logarithm */
ErrCode_Null, /* unable to allocate memory */
ErrCode_Indx, /* index out of range */
ErrCode_Ordr, /* minimum > maximum index */
ErrCode_Size, /* bit vector size mismatch */
ErrCode_Pars, /* input string syntax error */
ErrCode_Ovfl, /* numeric overflow error */
ErrCode_Same, /* operands must be distinct */
ErrCode_Expo, /* exponent must be positive */
ErrCode_Zero /* division by zero error */
} ErrCode;
typedef wordptr *listptr;
/* ===> MISCELLANEOUS BASIC FUNCTIONS: <=== */
charptr BitVector_Error (ErrCode error); /* return string for err code */
ErrCode BitVector_Boot (void); /* 0 = ok, 1..7 = error */
N_word BitVector_Size (N_int bits); /* bit vector size (# of words) */
N_word BitVector_Mask (N_int bits); /* bit vector mask (unused bits) */
/* ===> CLASS METHODS: <=== */
charptr BitVector_Version (void); /* return version string */
N_int BitVector_Word_Bits (void); /* return # of bits in machine word */
N_int BitVector_Long_Bits (void); /* return # of bits in unsigned long */
/* ===> CONSTRUCTOR METHODS: <=== */
wordptr BitVector_Create (N_int bits, boolean clear); /* malloc */
listptr BitVector_Create_List(N_int bits, boolean clear, N_int count);
wordptr BitVector_Resize (wordptr oldaddr, N_int bits); /* realloc */
wordptr BitVector_Shadow (wordptr addr); /* make new same size but empty */
wordptr BitVector_Clone (wordptr addr); /* make exact duplicate */
wordptr BitVector_Concat (wordptr X, wordptr Y); /* return concatenation */
/* ===> DESTRUCTOR METHODS: <=== */
void BitVector_Dispose (charptr string); /* string */
void BitVector_Destroy (wordptr addr); /* bitvec */
void BitVector_Destroy_List (listptr list, N_int count); /* list */
/* ===> OBJECT METHODS: <=== */
/* ===> bit vector copy function: */
void BitVector_Copy (wordptr X, wordptr Y); /* X = Y */
/* ===> bit vector initialization: */
void BitVector_Empty (wordptr addr); /* X = {} */
void BitVector_Fill (wordptr addr); /* X = ~{} */
void BitVector_Flip (wordptr addr); /* X = ~X */
void BitVector_Primes (wordptr addr);
/* ===> miscellaneous functions: */
void BitVector_Reverse (wordptr X, wordptr Y);
/* ===> bit vector interval operations and functions: */
void BitVector_Interval_Empty (wordptr addr, N_int lower, N_int upper);
void BitVector_Interval_Fill (wordptr addr, N_int lower, N_int upper);
void BitVector_Interval_Flip (wordptr addr, N_int lower, N_int upper);
void BitVector_Interval_Reverse (wordptr addr, N_int lower, N_int upper);
boolean BitVector_interval_scan_inc (wordptr addr, N_int start,
N_intptr min, N_intptr max);
boolean BitVector_interval_scan_dec (wordptr addr, N_int start,
N_intptr min, N_intptr max);
void BitVector_Interval_Copy (wordptr X, wordptr Y, N_int Xoffset,
N_int Yoffset, N_int length);
wordptr BitVector_Interval_Substitute(wordptr X, wordptr Y,
N_int Xoffset, N_int Xlength,
N_int Yoffset, N_int Ylength);
/* ===> bit vector test functions: */
boolean BitVector_is_empty (wordptr addr); /* X == {} ? */
boolean BitVector_is_full (wordptr addr); /* X == ~{} ? */
boolean BitVector_equal (wordptr X, wordptr Y); /* X == Y ? */
Z_int BitVector_Lexicompare(wordptr X, wordptr Y); /* X Y ? */
Z_int BitVector_Compare (wordptr X, wordptr Y); /* X Y ? */
/* ===> bit vector string conversion functions: */
charptr BitVector_to_Hex (wordptr addr);
ErrCode BitVector_from_Hex (wordptr addr, charptr string);
charptr BitVector_to_Bin (wordptr addr);
ErrCode BitVector_from_Bin (wordptr addr, charptr string);
charptr BitVector_to_Dec (wordptr addr);
ErrCode BitVector_from_Dec (wordptr addr, charptr string);
charptr BitVector_to_Enum (wordptr addr);
ErrCode BitVector_from_Enum (wordptr addr, charptr string);
/* ===> bit vector bit operations, functions & tests: */
void BitVector_Bit_Off (wordptr addr, N_int index); /* X = X \ {x} */
void BitVector_Bit_On (wordptr addr, N_int index); /* X = X + {x} */
boolean BitVector_bit_flip (wordptr addr, N_int index); /* (X+{x})\(X*{x}) */
boolean BitVector_bit_test (wordptr addr, N_int index); /* {x} in X ? */
void BitVector_Bit_Copy (wordptr addr, N_int index, boolean bit);
/* ===> bit vector bit shift & rotate functions: */
void BitVector_LSB (wordptr addr, boolean bit);
void BitVector_MSB (wordptr addr, boolean bit);
boolean BitVector_lsb_ (wordptr addr);
boolean BitVector_msb_ (wordptr addr);
boolean BitVector_rotate_left (wordptr addr);
boolean BitVector_rotate_right (wordptr addr);
boolean BitVector_shift_left (wordptr addr, boolean carry_in);
boolean BitVector_shift_right (wordptr addr, boolean carry_in);
void BitVector_Move_Left (wordptr addr, N_int bits);
void BitVector_Move_Right (wordptr addr, N_int bits);
/* ===> bit vector insert/delete bits: */
void BitVector_Insert (wordptr addr, N_int offset, N_int count,
boolean clear);
void BitVector_Delete (wordptr addr, N_int offset, N_int count,
boolean clear);
/* ===> bit vector arithmetic: */
boolean BitVector_increment (wordptr addr); /* X++ */
boolean BitVector_decrement (wordptr addr); /* X-- */
boolean BitVector_compute (wordptr X, wordptr Y, wordptr Z, boolean minus,
boolean *carry);
boolean BitVector_add (wordptr X, wordptr Y, wordptr Z, boolean *carry);
boolean BitVector_sub (wordptr X, wordptr Y, wordptr Z, boolean *carry);
boolean BitVector_inc (wordptr X, wordptr Y);
boolean BitVector_dec (wordptr X, wordptr Y);
void BitVector_Negate (wordptr X, wordptr Y);
void BitVector_Absolute (wordptr X, wordptr Y);
Z_int BitVector_Sign (wordptr addr);
ErrCode BitVector_Mul_Pos (wordptr X, wordptr Y, wordptr Z, boolean strict);
ErrCode BitVector_Multiply (wordptr X, wordptr Y, wordptr Z);
ErrCode BitVector_Div_Pos (wordptr Q, wordptr X, wordptr Y, wordptr R);
ErrCode BitVector_Divide (wordptr Q, wordptr X, wordptr Y, wordptr R);
ErrCode BitVector_GCD (wordptr X, wordptr Y, wordptr Z);
ErrCode BitVector_GCD2 (wordptr U, wordptr V, wordptr W, /* O */
wordptr X, wordptr Y); /* I */
ErrCode BitVector_Power (wordptr X, wordptr Y, wordptr Z);
/* ===> direct memory access functions: */
void BitVector_Block_Store(wordptr addr, charptr buffer, N_int length);
charptr BitVector_Block_Read (wordptr addr, N_intptr length);
/* ===> word array functions: */
void BitVector_Word_Store (wordptr addr, N_int offset, N_int value);
N_int BitVector_Word_Read (wordptr addr, N_int offset);
void BitVector_Word_Insert(wordptr addr, N_int offset, N_int count,
boolean clear);
void BitVector_Word_Delete(wordptr addr, N_int offset, N_int count,
boolean clear);
/* ===> arbitrary size chunk functions: */
void BitVector_Chunk_Store(wordptr addr, N_int chunksize,
N_int offset, N_long value);
N_long BitVector_Chunk_Read (wordptr addr, N_int chunksize,
N_int offset);
/* ===> set operations: */
void Set_Union (wordptr X, wordptr Y, wordptr Z); /* X = Y + Z */
void Set_Intersection (wordptr X, wordptr Y, wordptr Z); /* X = Y * Z */
void Set_Difference (wordptr X, wordptr Y, wordptr Z); /* X = Y \ Z */
void Set_ExclusiveOr (wordptr X, wordptr Y, wordptr Z); /*(Y+Z)\(Y*Z)*/
void Set_Complement (wordptr X, wordptr Y); /* X = ~Y */
/* ===> set functions: */
boolean Set_subset (wordptr X, wordptr Y); /* X in Y ? */
N_int Set_Norm (wordptr addr); /* = | X | */
N_int Set_Norm2 (wordptr addr); /* = | X | */
N_int Set_Norm3 (wordptr addr); /* = | X | */
Z_long Set_Min (wordptr addr); /* = min(X) */
Z_long Set_Max (wordptr addr); /* = max(X) */
/* ===> matrix-of-booleans operations: */
void Matrix_Multiplication(wordptr X, N_int rowsX, N_int colsX,
wordptr Y, N_int rowsY, N_int colsY,
wordptr Z, N_int rowsZ, N_int colsZ);
void Matrix_Product (wordptr X, N_int rowsX, N_int colsX,
wordptr Y, N_int rowsY, N_int colsY,
wordptr Z, N_int rowsZ, N_int colsZ);
void Matrix_Closure (wordptr addr, N_int rows, N_int cols);
void Matrix_Transpose (wordptr X, N_int rowsX, N_int colsX,
wordptr Y, N_int rowsY, N_int colsY);
/*****************************************************************************/
/* MODULE RESOURCES: */
/*****************************************************************************/
#define bits_(BitVector) *(BitVector-3)
#define size_(BitVector) *(BitVector-2)
#define mask_(BitVector) *(BitVector-1)
#define ERRCODE_TYPE "sizeof(word) > sizeof(size_t)"
#define ERRCODE_BITS "bits(word) != sizeof(word)*8"
#define ERRCODE_WORD "bits(word) < 16"
#define ERRCODE_LONG "bits(word) > bits(long)"
#define ERRCODE_POWR "bits(word) != 2^x"
#define ERRCODE_LOGA "bits(word) != 2^ld(bits(word))"
#define ERRCODE_NULL "unable to allocate memory"
#define ERRCODE_INDX "index out of range"
#define ERRCODE_ORDR "minimum > maximum index"
#define ERRCODE_SIZE "bit vector size mismatch"
#define ERRCODE_PARS "input string syntax error"
#define ERRCODE_OVFL "numeric overflow error"
#define ERRCODE_SAME "result vector(s) must be distinct"
#define ERRCODE_EXPO "exponent must be positive"
#define ERRCODE_ZERO "division by zero error"
#define ERRCODE_OOPS "unexpected internal error - please contact author"
extern const N_int BitVector_BYTENORM[256];
/*
{
0x00, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02, 0x03,
0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04,
0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04,
0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04,
0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04,
0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07,
0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04,
0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07,
0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07,
0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07,
0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07,
0x05, 0x06, 0x06, 0x07, 0x06, 0x07, 0x07, 0x08
};
*/
/*****************************************************************************/
/* MODULE IMPLEMENTATION: */
/*****************************************************************************/
/*****************************************************************************/
/* VERSION: 6.4 */
/*****************************************************************************/
/* VERSION HISTORY: */
/*****************************************************************************/
/* */
/* Version 6.4 03.10.04 Added C++ comp. directives. Improved "Norm()". */
/* Version 6.3 28.09.02 Added "Create_List()" and "GCD2()". */
/* Version 6.2 15.09.02 Overhauled error handling. Fixed "GCD()". */
/* Version 6.1 08.10.01 Make VMS linker happy: _lsb,_msb => _lsb_,_msb_ */
/* Version 6.0 08.10.00 Corrected overflow handling. */
/* Version 5.8 14.07.00 Added "Power()". Changed "Copy()". */
/* Version 5.7 19.05.99 Quickened "Div_Pos()". Added "Product()". */
/* Version 5.6 02.11.98 Leading zeros eliminated in "to_Hex()". */
/* Version 5.5 21.09.98 Fixed bug of uninitialized "error" in Multiply. */
/* Version 5.4 07.09.98 Fixed bug of uninitialized "error" in Divide. */
/* Version 5.3 12.05.98 Improved Norm. Completed history. */
/* Version 5.2 31.03.98 Improved Norm. */
/* Version 5.1 09.03.98 No changes. */
/* Version 5.0 01.03.98 Major additions and rewrite. */
/* Version 4.2 16.07.97 Added is_empty, is_full. */
/* Version 4.1 30.06.97 Added word-ins/del, move-left/right, inc/dec. */
/* Version 4.0 23.04.97 Rewrite. Added bit shift and bool. matrix ops. */
/* Version 3.2 04.02.97 Added interval methods. */
/* Version 3.1 21.01.97 Fixed bug on 64 bit machines. */
/* Version 3.0 12.01.97 Added flip. */
/* Version 2.0 14.12.96 Efficiency and consistency improvements. */
/* Version 1.1 08.01.96 Added Resize and ExclusiveOr. */
/* Version 1.0 14.12.95 First version under UNIX (with Perl module). */
/* Version 0.9 01.11.93 First version of C library under MS-DOS. */
/* Version 0.1 ??.??.89 First version in Turbo Pascal under CP/M. */
/* */
/*****************************************************************************/
/* AUTHOR: */
/*****************************************************************************/
/* */
/* Steffen Beyer */
/* mailto:sb@engelschall.com */
/* http://www.engelschall.com/u/sb/download/ */
/* */
/*****************************************************************************/
/* COPYRIGHT: */
/*****************************************************************************/
/* */
/* Copyright (c) 1995 - 2004 by Steffen Beyer. */
/* All rights reserved. */
/* */
/*****************************************************************************/
/* LICENSE: */
/*****************************************************************************/
/* */
/* This library is free software; you can redistribute it and/or */
/* modify it under the terms of the GNU Library General Public */
/* License as published by the Free Software Foundation; either */
/* version 2 of the License, or (at your option) any later version. */
/* */
/* This library is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
/* Library General Public License for more details. */
/* */
/* You should have received a copy of the GNU Library General Public */
/* License along with this library; if not, write to the */
/* Free Software Foundation, Inc., */
/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* */
/* or download a copy from ftp://ftp.gnu.org/pub/gnu/COPYING.LIB-2.0 */
/* */
/*****************************************************************************/
#ifdef __cplusplus
}
#endif
#endif
psad-7c4a910/deps/Bit-Vector/CHANGES.txt 0000664 0000000 0000000 00000031712 12071203757 0017525 0 ustar 00root root 0000000 0000000 =====================================
Package "Bit::Vector" Version 6.4
=====================================
Copyright (c) 1995 - 2004 by Steffen Beyer.
All rights reserved.
Version history:
----------------
Version 6.4 03.10.2004
+ Added compiler directives for C++.
+ Improved the method "Norm()".
+ Removed "Carp::Clan" from the distribution (available separately).
+ Added "Bit::Vector::String" for generic string import/export functions.
+ Added a new test file "t/40__auxiliary.t" for "Bit::Vector::String".
+ Fixed a bug in method "Copy()" concerning sign (MSB) extension.
Version 6.3 28.09.2002
+ Added "Create_List()" and "GCD2()" in "BitVector.c".
+ "new()" now can optionally return a list of bit vectors.
+ "GCD()" now can optionally return the two integer factors
"x" and "y" for the linear combination of its input values
"a" and "b" so that gcd(a,b) = x * a + y * b.
+ Changed the test files "t/01________new.t" and "t/09_parameters.t"
as well as the documentation accordingly.
+ Added a new test file "t/17________gcd.t".
+ Further simplified the error handlers in "Vector.xs", making the
resulting object library file substantially smaller (about 20%!)
and thus faster to load.
Version 6.2 15.09.2002
+ Fixed missing "\" in regular expression in "t/00____version.t".
+ Overhauled the error handlers in "BitVector.c" and "Vector.xs".
+ Added a demo "examples/test.c" to play around with the C library.
+ Attempted to fix all compiler warnings.
+ Fixed a problem in test "t/01________new.t" with Perl using
64 bit integers; now contains "use integer;" to avoid failure.
+ Synchronized "Carp::Clan" and "ToolBox.h" with "Date::Calc" 5.2.
+ Revealed common method aliases (Or, And, etc.) in the documentation.
+ Fixed GCD(), now GCD(z,0) == GCD(0,z) == z and negative values
are handled correctly.
Version 6.1 08.10.2001
+ Fixed the problem which caused some of the tests with overloaded
operators to fail under Perl 5.7.1 and Perl 5.7.2.
+ Added the module "Carp::Clan" to the distribution.
+ Changed most of the error messages in Bit::Vector::Overload.
+ Changed the test script "t/30_overloaded.t" accordingly.
+ Changed "Makefile.PL" to write a "patchlevel.h" file so that
"Vector.xs" can automatically detect the Perl version and
whether to use the macro PL_na or na, GIMME_V or GIMME.
Tweaking the code before installing is not necessary anymore.
+ Changed the documentation in files README.txt and INSTALL.txt
accordingly.
+ Changed the internal names BitVector_msb and BitVector_lsb to
BitVector_msb_ and BitVector_lsb_ in order to make the (non-
ANSI C-standard-compliant!) VMS linker happy. This does NOT
affect the Perl interface, though.
Version 6.0 08.10.2000
+ Splitted the Vector.pm module; separated XS and overloaded Perl
part for improved performance (reduces loading time for XS part).
+ Corrected the handling of numerical overflow in arithmetic methods
("add()", "subtract()", "Multiply()", "from_Dec()", "new_Dec()").
+ Methods "add()" and "subtract()" now return the carry as well as
the overflow flag if called in list context (only the carry in
scalar context, as before).
+ Added two new methods "inc()" and "dec()", which return the overflow
flag (whereas "increment()" and "decrement()" return the carry flag).
The new methods also allow to copy-and-increment/decrement in addition
to in-place operation.
+ Methods "from_Dec()" and "new_Dec()" now allow you to enter large
positive numbers which will have the MSB set (this was forbidden
previously because these numbers are considered to be negative in
two's complement binary representation).
Version 5.8 14.07.2000
+ Changed "na" to "PL_na" in Vector.xs in order to make the module
ready for Perl 5.6.0.
+ Removed the error messages which appeared at global destruction
time with Perl 5.6.0.
+ Changed the corresponding test script (t/02____destroy.t) accordingly.
+ Optimized the "strEQ" away from the typemap section in Vector.xs.
+ Fixed the misspelled word "whether" in the documentation.
+ Added method "Power()".
+ Added overloaded operator "**" (for exponentiation).
+ Changed method "Copy()"; the two vectors do not need to have the same
size anymore. The method will copy as much as will fit or fill up
with 0's or 1's (depending on the sign of the source) if necessary.
+ Changed the corresponding test script (t/09_parameters.t) accordingly.
Version 5.7 19.05.1999
+ Improved method "Div_Pos()": It now uses only one instead of the
former two (very costly) "shift" operations in its main loop, and
it now depends on the (variable) length of the numbers involved rather
than the (constant) length of their respective bit vectors, making
this method tremendously faster now. The methods "to_Dec()", "Divide()"
and "GCD()" also profit from this change in the same way since they
rely crucially on the "Div_Pos()" method, internally.
+ Added a matrix multiplication method (for "Math::MatrixBool") named
"Product()" which determines paths in matrices representing graphs.
+ Fixed the problems with anchored error messages in the regression
test suite under MacPerl.
Version 5.6 02.11.1998
+ Removed the leading zeros from the output of "to_Hex()".
+ Fixed compiler warning on line 2067 of "BitVector.c".
Version 5.5 21.09.1998
+ Fixed the bug of the uninitialized return code in method "Multiply()".
+ Fixed the failure of tests 96-131 of test script "t/01________new.t"
under HP-UX 10.
Version 5.4 07.09.1998
+ Fixed the bug of the uninitialized return code in method "Divide()".
+ Introduced an additional header "Preface" in the POD documentation to
avoid clobbering of the information displayed by CPAN.pm et al.
+ Added the new attributes to "Makefile.PL" for ActiveState's port
of Perl 5.005 to the Win32 platform.
Version 5.3 12.05.1998
+ Changed "Norm()" to become still a bit more efficient.
+ Ported the "upgrade_BV52" utility to Perl ("upgrade_BV53.pl"),
making it faster, more flexible and easier to read and maintain.
+ Added "upgrade_BV42.pl".
+ Enhanced support for Windows NT/95.
+ Complete rewrite of this "CHANGES.txt" document.
Version 5.2 31.03.1998
+ Changed "Norm()", "<>" to become more efficient.
+ Added "new_Hex()", "new_Bin()", "new_Dec()" and "new_Enum()".
+ Made the exception handling in "Vector.pm" more elegant.
Version 5.1 09.03.1998
+ Added systematic exception handling to "Vector.pm".
Version 5.0 01.03.1998
+ "Outsourced" all example modules (now available separately).
+ Added: Word_Bits(), Long_Bits(), Concat(), Concat_List(), Primes(),
Reverse(), Interval_Reverse(), Interval_Copy(), Interval_Substitute(),
Lexicompare(), to_Bin(), from_Bin(), to_Dec(), from_Dec(), Bit_Copy(),
LSB(), MSB(), lsb(), msb(), Insert(), Delete(), add(), subtract(),
Negate(), Absolute(), Sign(), Multiply(), Divide(), GCD(), Block_Store(),
Block_Read(), Word_Size(), Word_Store(), Word_Read(), Word_List_Store(),
Word_List_Read(), Word_Insert(), Word_Delete(), Chunk_Store(),
Chunk_Read(), Chunk_List_Store(), Chunk_List_Read(), Index_List_Remove(),
Index_List_Store(), Index_List_Read(), Transpose().
+ Ported to C: "Version()", "Shadow()", "Clone()", "to_Enum()",
"from_Enum()".
+ Changed: "Compare()" (now assumes bit vectors are SIGNED).
+ Renamed: "to_String()" ==> "to_Hex()", "from_string()" ==> "from_Hex()",
"to_ASCII()" ==> "to_Enum()", "from_ASCII()" ==> "from_Enum()"
(aliases are still available but deprecated).
+ Dropped: "lexorder()", "new_from_String()".
+ Dropped: Module "Set::IntegerFast" (replaced by "Bit::Vector").
+ Definitely abandoned the possibility for subclassing because it doesn't
make any sense in this module (use embedding instead!).
+ Fixed: Module "Set::IntegerRange" version 4.2 broke with "Bit::Vector"
version 5.0. Issued quick fix "Set::IntRange" version 5.0. More
thorough implementation is under construction.
Version 4.2 16.07.1997
+ Added "is_empty()" and "is_full()".
Version 4.1 30.06.1997
+ Added "Move_Left()" and "Move_Right()".
+ Changed "<>" to call "Move_Left()" and "Move_Right()" instead.
+ Added "increment()" and "decrement()".
+ Changed "++" and "--" to call "increment()" and "decrement()" instead.
+ Added "Resize()", "Interval_Scan_inc()", "Interval_Scan_dec()" and
"BitVector()" to "Set::IntegerRange".
Version 4.0 23.04.1997
+ Complete rewrite of the "Set::IntegerFast" module.
+ Renamed "Set::IntegerFast" to "Bit::Vector".
+ United the separate C cores and XS files for sets, matrices of booleans
and bit shift operations in a single module.
+ Abandoned the individual version numbers.
+ Dropped the separate "Makefile.PL"s, adopted the solution using
a "lib" subdirectory.
+ Added: Flip(), Interval_Scan_inc(), Interval_Scan_dec(), rotate_left(),
rotate_right(), shift_left(), shift_right(), to_String(), from_string(),
Multiplication(), Closure(), Shadow(), Clone(), new_from_String(),
to_ASCII(), from_ASCII().
+ Added overloaded operators for: emptyness, equality, lexical comparison,
shift register, rotate register, string conversion, union, intersection,
difference, exclusive-or, complement, subset relationship, true subset
relationship, superset relationship, true superset relationship, norm.
Version 3.2 04.02.1997
+ Added "Empty_Interval()", "Fill_Interval()", "Flip_Interval()" and
"Size()" to "Set::IntegerFast" and "Set::IntegerRange".
+ "Set::IntegerFast" and "Set::IntegerRange" both switched to version
number 3.0.
+ Improved the "Math::MatrixBool" module (new version number: 2.0) to
use C routines for matrix multiplication and closure and fixed some
bugs in these methods at the same time.
+ Added "new_from_string()" and "Dim()" to "Math::MatrixBool".
+ Fixed a severe bug in the "kleene()" method of "Math::MatrixReal"
(new version number: 1.1).
Version 3.1 21.01.1997
+ Fixed a bug that caused the initialization routine of the module to fail
on 64 bit machines due to a wrong conditional expression (type "int" and
"size_t" do not necessarily have the same size!).
+ "Set::IntegerFast" switched to version number 2.2.
Version 3.0 12.01.1997
+ Added "flip()" to "Set::IntegerFast" and "Set::IntegerRange".
+ Transformed the "kruskal" demo program to a Perl module "Graph::Kruskal".
+ Added new companion modules: "Math::MatrixBool", "Math::MatrixReal" and
"DFA::Kleene", all with separate "Makefile.PL"s.
+ Added introductory article about theory behind Kleene's algorithm.
+ Introduced independent version numbers for all modules:
"Set::IntegerFast" ==> version 2.1, "Set::IntegerRange" ==> version 2.0.
+ Added overloaded operators to "Set::IntegerRange".
+ Bugfix: Changed "gv_stashpv(class,0)" to "gv_stashpv(class,1)" in the
XS file (caused core dumps in previous versions when "new()" was called
with a nonexistent class name and subclassing enabled).
Version 2.0 14.12.1996
+ Changed "Create()" to "new()".
+ Now supports "$set = new Set::IntegerFast($elements);" instead of
"$set = Set::IntegerFast::Create($elements);".
+ Changed "Destroy()" to "DESTROY()", which doesn't need to (and
shouldn't!) be called explicitly anymore.
+ Fixed the "bad free() ignored" warnings caused by "Destroy()" in
version 1.1 (in conjunction with Perl version 5.002) which led some
of the tests in "make test" to fail.
+ Complete rewrite of the XS part.
+ Changed "lexorder()" and "Compare()" to become more efficient
(complexity n/b instead of n/8).
+ Changed parameters visible externally from "word"/"unit" to "N_int"
in the C core.
+ Complete rewrite of the documentation, now in POD format.
+ Added a new (wrapper) module named "Set::IntegerRange".
Version 1.1 08.01.1996
+ Added "Resize()".
+ Changed "Create()", "Empty()", "Fill()" and "Copy()" to have complexity
n/b rather than n/8.
+ Made interfaces in C core more consistent: Pointer to a set object is
now always the first parameter.
+ Added new paragraphs to the documentation.
+ Added "ExclusiveOr()" (for symmetric difference X = (Y + Z) \ (Y * Z)).
Version 1.0 14.12.1995 First version under UNIX (with Perl module).
+ Initial release as a C library and Perl module.
Version 0.9 01.11.1993 First version of C library under MS-DOS.
+ Ported the Pascal code to C because I thought sets of arbitrary sizes
are always useful to have.
Version 0.1 ??.??.1989 First version in Turbo Pascal under CP/M.
+ I first wrote this library (on my Apple ][+) because I needed more bits
in a set than Turbo Pascal would support in order to calculate "first",
"follow" and "look-ahead" character sets for a compiler-compiler.
----------------------------------------------------------------------------
psad-7c4a910/deps/Bit-Vector/CREDITS.txt 0000664 0000000 0000000 00000021704 12071203757 0017552 0 ustar 00root root 0000000 0000000 =====================================
Package "Bit::Vector" Version 6.4
=====================================
Copyright (c) 1995 - 2004 by Steffen Beyer.
All rights reserved.
Credits:
--------
Many thanks to Andreas Koenig for his
efforts as upload-manager for the CPAN, his patience, and lots of good
advice and suggestions! Thank you for doing such a tremendous (and time-
consuming) job!!
Also many thanks to David Jenkins for reviewing the
first version of the README file and the man page.
Many thanks to Jarkko Hietaniemi for his
suggestions while I was developing the first release of this package!
Many thanks also to the people of the perl5-porters
mailing list, specifically:
Andreas Koenig
Tim Bunce
Jarkko Hietaniemi
Felix Gallo
Mark A Biggar
Nick Ing-Simmons
John Macdonald
for discussing and clarifying the naming and other issues of this package!
Also many thanks to David Thompson for reporting a
problem he encountered concerning the inclusion of the Perl distribution
("Unable to find include file ...") and for suggesting a solution for this
problem. (That's the most pleasant kind of problem report, of course! ;-) )
Many thanks to Rob Johnson for an improved algorithm
for computing binomials with always integer intermediate results (and
numbers never getting too big)!
Thanks to Banchong Harangsri for reporting the
problem of the version 1.1 of this module with Perl 5.002!
Special thanks to Dean Roehrich for his assistance
in trying to find the cause of and a remedy for the above problem!
Many thanks to Andreas Koenig for notifying me of the alternative for the
directory structure using the "lib" subdirectory and a way to use "confess"
in an XSUB via "perl_eval_sv".
Many special thanks to Larry Schwimmer for
reporting the bug related to 64 bit machines and finding where an implicit
assumption of 32 bit integers was hidden, and for testing the new version
on his machine!
Many thanks to Ralf S. Engelschall for suggesting
the four new methods "Size()", "Empty_Interval()", "Fill_Interval()" and
"Flip_Interval()", implemented in version 3.0 of the "Set::IntegerFast"
module (and also in the "Set::IntegerRange" module)!
Also many thanks to Ralf Engelschall for the many good suggestions that
went into version 4.0 of this package (concerning many different aspects)!
Many thanks to Stas Bekman for raising the question
of bitwise shift and rotation operations in Perl, which gave me the idea to
implement such shift registers with arbitrary size, which in turn and with
time gave me the idea of implementing a "Bit::Vector" base class capable of
this along with already existing functionality (for sets and boolean matrices).
Also many thanks to Jon Orwant and Tim Bunce
for their suggestions and comments concerning my
first attempts at writing a module for bitwise shift and rotate operations
in Perl, which eventually went into version 4.0 of this module!
Many thanks to Brian S. Julin for sharing his ideas, his
questions and the code of his "Bit::File" module with me, which inspired
me to write the routines to access arbitrary chunks of bits.
Many thanks to Hau-Yung Chen for suggesting the
string conversion routines to convert to/from binary representation
and the possibility to concatenate bit vectors.
Many thanks to Jarkko Hietaniemi for suggesting
the implementation of the transpose of a matrix in C for better performance.
The transpose can be used in finding the strongly connected components of
a graph.
Many thanks go to Daniel Koch for suggesting the
"Index_List_Store()" and "Index_List_Read()" methods!
Many thanks again to Hau-Yung Chen for suggesting
a way for speeding up the conversion to decimal in "to_Dec()" (by dividing
the bit vector through the largest possible power of ten that will fit into
a machine word and then breaking down the rest using only machine words,
which is faster than repeatedly dividing the whole bit vector by ten).
According to my measurements, this resulted in an 8-fold speed increase.
Many thanks go to Krzysztof Koczyjan for
suggesting and extensively benchmarking a more efficient method for
bit counting in the method "Norm()", which was adopted in version 5.2.
Many thanks again to Krzysztof Koczyjan for
an additional improvement of the method "Norm()", which was adopted in
version 5.3.
Many thanks to Bryan Bayerdorffer for
notifying me of the bug in the "Divide()" method, which was immediately
fixed in version 5.4.
Many thanks to Rob W. Koeling for reporting and to
Paul J. Schinder for reporting and helping to investigate
the error of the failed tests 96-131 of test script "t/01________new.t" under
HP-UX 10! This was fixed in version 5.5.
Many thanks to the "CPAN testers" (http://www.connect.net/gbarr/cpan-test/)
in general and to Jarkko Hietaniemi in particular for testing
this module and for reporting the compiler warning which occurred on line
2067 of "BitVector.c" with the native "cc" compiler under Digital Unix,
which has been fixed in version 5.6.
Also many thanks to Matt Knecht for pushing me hard
enough ;-) to suppress those annoying leading zeros in the output from
"to_Hex()" in version 5.6!
Many thanks to Roland Titze and
to Andrew Brown for pointing out the
misspelling of "whether" (was: wether) throughout my documentation,
corrected in version 5.8.
Thanks also go to Steve Tolkin for suggesting that
I should emphasize in the README.txt file that the reading of the INSTALL.txt
file is important, especially if running Perl under Windows. :-)
Many special thanks to Joshua N. Pritikin for
sending in valuable patches to make this module ready for Perl 5.6.0
and to optimize the "strEQ" away from the typemap section in Vector.xs.
Lots of thanks also to Yitzchak Scott-Thoennes for
sending in a patch to make this module ready for Perl 5.6.0 and for
extremely useful hints (and a patch) as to why the test suite had
failures with Perl 5.6.0 all of a sudden.
Many thanks to John Peacock for reporting a
problem with the VMS linker which is unable to differentiate case -
in violation of the ANSI C standard - and for sending a patch to fix
this problem.
Many thanks to Tom Oelke for reporting a
problem with test "t/01________new.t" when Perl was built to use
64 bit integers and for suggesting two possible fixes. The second
one (adding "use integer;" at the top of the script) was adopted
in version 6.2.
Many thanks to Clint Olsen for his many interesting
questions and suggestions, one of which led to my writing the new
example file "examples/test.c" in version 6.2.
Many thanks to Tels for his criticism of "GCD()"
and the documentation (with respect to common method name aliases
such as Or, And, Xor, etc.). Both weaknesses have been fixed in
version 6.2.
Many thanks to Mike Swieton (and many other
people in the past) for sending in a patch so that ToolBox.h will compile
with C++ compilers.
Many thanks to Runip Gopisetty for sending
a patch for adding functions for generic string import and export functions.
However, I decided to realize these in Perl instead (at least for the time
being); you can find them in the new module "Bit::Vector::String". This way
even octal representation and enumerations are supported.
Many heartfelt thanks go to Jamie Blustein /
/ for sending me the article
"Performance Investigation of Bit-Counting Algorithms with a
Speedup to Lookup Table", by Eyas El-Qawasmeh, Department of
Computer Science and Information Systems, Jordan University of
Science and Technology, cited from the Journal of Research and
Practice in Information Technology, Vol. 32, No. 3/4, August/
November 2000, thus prompting my reconsideration of the
implementation of the "Norm()" method in this module.
See also his web pages, especially the pages about bit vectors,
at:
http://www.cs.dal.ca/~jamie/
http://www.csd.uwo.ca/~jamie/
http://www.csd.uwo.ca/%7ejamie/.Refs/code.html
http://www.csd.uwo.ca/%7ejamie/publications.html#BitVectors
http://www.csd.uwo.ca/~jamie/BitVectors/
psad-7c4a910/deps/Bit-Vector/GNU_GPL.txt 0000664 0000000 0000000 00000043101 12071203757 0017603 0 ustar 00root root 0000000 0000000 GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
Copyright (C) 19yy
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.
psad-7c4a910/deps/Bit-Vector/GNU_LGPL.txt 0000664 0000000 0000000 00000061271 12071203757 0017727 0 ustar 00root root 0000000 0000000 GNU LIBRARY GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the library GPL. It is
numbered 2 because it goes with version 2 of the ordinary GPL.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Library General Public License, applies to some
specially designated Free Software Foundation software, and to any
other libraries whose authors decide to use it. You can use it for
your libraries, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if
you distribute copies of the library, or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link a program with the library, you must provide
complete object files to the recipients so that they can relink them
with the library, after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
Our method of protecting your rights has two steps: (1) copyright
the library, and (2) offer you this license which gives you legal
permission to copy, distribute and/or modify the library.
Also, for each distributor's protection, we want to make certain
that everyone understands that there is no warranty for this free
library. If the library is modified by someone else and passed on, we
want its recipients to know that what they have is not the original
version, so that any problems introduced by others will not reflect on
the original authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that companies distributing free
software will individually obtain patent licenses, thus in effect
transforming the program into proprietary software. To prevent this,
we have made it clear that any patent must be licensed for everyone's
free use or not licensed at all.
Most GNU software, including some libraries, is covered by the ordinary
GNU General Public License, which was designed for utility programs. This
license, the GNU Library General Public License, applies to certain
designated libraries. This license is quite different from the ordinary
one; be sure to read it in full, and don't assume that anything in it is
the same as in the ordinary license.
The reason we have a separate public license for some libraries is that
they blur the distinction we usually make between modifying or adding to a
program and simply using it. Linking a program with a library, without
changing the library, is in some sense simply using the library, and is
analogous to running a utility program or application program. However, in
a textual and legal sense, the linked executable is a combined work, a
derivative of the original library, and the ordinary General Public License
treats it as such.
Because of this blurred distinction, using the ordinary General
Public License for libraries did not effectively promote software
sharing, because most developers did not use the libraries. We
concluded that weaker conditions might promote sharing better.
However, unrestricted linking of non-free programs would deprive the
users of those programs of all benefit from the free status of the
libraries themselves. This Library General Public License is intended to
permit developers of non-free programs to use free libraries, while
preserving your freedom as a user of such programs to change the free
libraries that are incorporated in them. (We have not seen how to achieve
this as regards changes in header files, but we have achieved it as regards
changes in the actual functions of the Library.) The hope is that this
will lead to faster development of free libraries.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, while the latter only
works together with the library.
Note that it is possible for a library to be covered by the ordinary
General Public License rather than by this special one.
GNU LIBRARY GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library which
contains a notice placed by the copyright holder or other authorized
party saying it may be distributed under the terms of this Library
General Public License (also called "this License"). Each licensee is
addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also compile or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
c) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
d) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the source code distributed need not include anything that is normally
distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Library General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
Copyright (C)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!
psad-7c4a910/deps/Bit-Vector/INSTALL.txt 0000664 0000000 0000000 00000021261 12071203757 0017561 0 ustar 00root root 0000000 0000000 =====================================
Package "Bit::Vector" Version 6.4
=====================================
Copyright (c) 1995 - 2004 by Steffen Beyer.
All rights reserved.
Contents:
---------
+ Prerequisites
+ Preliminary steps for use with Perl prior to version 5.002
+ Preliminary steps for use with ActiveState's port of Perl 5
+ How to install additional languages
+ Installation
Prerequisites:
--------------
Perl version 5.000 or higher, and an ANSI C compiler. (!)
^^^^^^
Module "Carp::Clan" version 5.0 or higher.
Note that in order to compile Perl modules which contain
C (and/or XS) code (such as this one), you always HAVE
to use the very same compiler your Perl itself was compiled
with.
Many vendors nowadays ship their operating system already
comprising a precompiled version of Perl. Many times the
compilers used to compile this version of Perl are not
available to or not usually used by the users of these
operating systems.
In such cases building this module (or any other Perl
module containing C and/or XS code) will not work. You
will either have to get the compiler which was used to
compile Perl itself (see for example the section "Compiler:"
in the output of the command "perl -V"), or to build
your own Perl with the compiler of your choice (which
also allows you to take advantage of the various compile-
time switches Perl offers).
Note that Sun Solaris and Red Hat Linux frequently were
reported to suffer from this kind of problem.
Moreover, you usually cannot build any modules under
Windows 95/98 since the Win 95/98 command shell doesn't
support the "&&" operator. You will need the Windows NT
command shell ("cmd.exe") or the "4DOS" shell to be
installed on your Windows 95/98 system first. Note that
Windows NT and Windows 2000 are not affected and just
work fine. I don't know about Windows XP, however.
Note that ActiveState provides precompiled binaries of
this module for their Win32 port of Perl ("ActivePerl")
on their web site, which you should be able to install
simply by typing "ppm install Bit-Vector" in your MS-DOS
command shell (but note the "-" instead of "::" in the
package name!). This also works under Windows 95/98 (!).
If your firewall prevents "ppm" from downloading
this package, you can also download it manually from
http://www.activestate.com/ppmpackages/5.005/zips/ or
http://www.activestate.com/ppmpackages/5.6/zips/.
Follow the installation instructions included in
the "zip" archive.
Preliminary steps for use with Perl prior to version 5.002:
-----------------------------------------------------------
Edit the file "Makefile.PL" and change the line
'VERSION_FROM' => 'Vector.pm',
to
'VERSION' => '6.4',
Then edit the file "Vector.pm" and change the line
bootstrap Bit::Vector $VERSION;
to
bootstrap Bit::Vector;
Also edit the file "t/00____version.t" and change the line
use Bit::Vector 6.4;
to
use Bit::Vector;
Finally, edit the file "Vector.xs" and delete the line
PROTOTYPES: DISABLE
Preliminary steps for use with ActiveState's port of Perl 5:
------------------------------------------------------------
(For the Win32 platform)
Edit the file "Makefile.PL" and remove all of the "#" characters
which currently comment out the lines involved with the setting
of the attributes "ABSTRACT", "AUTHOR" and "CAPI".
Installation:
-------------
=============================================================================
ALWAYS unpack and build Perl modules OUTSIDE the Perl source and installation
tree! (You might otherwise inadvertently corrupt your Perl installation!)
=============================================================================
Quick installation guide for experienced users:
-----------------------------------------------
UNIX: Win32/Borland C++: Win32/MS Visual C++:
===== ================== ====================
% perl Makefile.PL % perl Makefile.PL % perl Makefile.PL
% make % dmake % nmake
% make test % dmake test % nmake test
% make install % dmake install % nmake install
Detailed installation guide:
----------------------------
1) Change directory to the directory that has been created by unpacking this
package ("cd Bit-Vector-6.4").
2) Type "perl Makefile.PL" (or whatever the name and path of your Perl 5
binary is).
This will create a "Makefile" with the appropriate parameters for your
system (for instance, where the install directories are, and so on).
See "man ExtUtils::MakeMaker" or "perldoc ExtUtils::MakeMaker" for
other useful options to this command, like setting a different
installation PREFIX.
3) Type "make".
(For installation under Windows NT/95, use "dmake" (Borland C++) or
"nmake" (MS Visual C++) instead!)
This will create a dynamically linkable library file that will be linked
to Perl later, at runtime, provided your system supports dynamic linking.
Please refer to the MakeMaker documentation for instructions on how
to build a new Perl with statically linked libraries (invoke "perldoc
ExtUtils::MakeMaker" for this), if your system does NOT support dynamic
linking!
Should you encounter any compiler warnings or errors (like the redefi-
nition of certain types already defined by your system), please contact
me via e-mail at , sending me your compiler output
(both STDOUT and STDERR). Thank you!
======================================================================
BEWARE that you need an ANSI C compiler in order to successfully
compile this package!
======================================================================
Also note that problems may arise with the c89 compiler of HP, although
it allegedly supports ANSI C!
I recommend the GNU C compiler ("gcc"), which is freely available on
the Internet (see ftp://ftp.gnu.org/pub/gnu/ and mirror sites thereof).
(HP users are strongly recommended to install the GNU assembler "gas"
first before installing the GNU C compiler "gcc", according to GNU.)
Should you get the error messages
Vector.c: 15: Unable to find include file 'EXTERN.h'.
Vector.c: 16: Unable to find include file 'perl.h'.
Vector.c: 17: Unable to find include file 'XSUB.h'.
then edit the file "Makefile.PL" and add a line similar to the
following so that it points to your Perl 5 distribution tree:
'INC' => '-I/usr/ctr/dlt/private/perl/perl5.003',
Then start over with the generation of the "Makefile" at 2).
4) Now issue "make test" (or "dmake test" or "nmake test", respectively).
The output should look somewhat like this:
PERL_DL_NONLAZY=1 /sw/bin/perl -Iblib/arch
-Iblib/lib -I/sw/pkg/perl/lib/5.00503/i386-freebsd
-I/sw/pkg/perl/lib/5.00503 -e 'use Test::Harness
qw(&runtests $verbose); $verbose=0; runtests @ARGV;' t/*.t
t/00____version.....ok
t/01________new.....ok
t/02____destroy.....ok
t/03_operations.....ok
t/04__functions.....ok
t/05_____primes.....ok
t/06_____subset.....ok
t/07____compare.....ok
t/08_____resize.....ok
t/09_parameters.....ok
t/10__intervals.....ok
t/11______shift.....ok
t/12_____string.....ok
t/13__increment.....ok
t/14______empty.....ok
t/15________add.....ok
t/16___subtract.....ok
t/17________gcd.....ok
t/28__chunklist.....ok
t/30_overloaded.....ok
t/40__auxiliary.....ok
All tests successful.
Files=21, Tests=68151, 29 wallclock secs
(19.75 cusr + 0.73 csys = 20.48 CPU)
(Note that the exact number of tests will depend on the number of bits
of a machine word/an unsigned long on your system!)
5) At last, type "make install" (or "dmake install", "nmake install").
6) Now you can run the "primes.pl" demo program from the "examples" sub-
directory, for instance. Start it with "perl examples/primes.pl" (or
whatever the name and path of your Perl 5 binary is).
It will ask you to enter a number which will serve as an upper limit for
the calculation of all prime numbers up to that limit, using the algorithm
known as "The Sieve of Erathostenes".
On my machine (SUN SPARCstation 20/61), calculating all the prime numbers
up to one million takes about 1 minute 30 seconds to 2 minutes (depending
on the load) when the algorithm is programmed in Perl. If the internal
method "Primes()" is used instead (implemented in C), the same machine
only takes about 1 second for this task.
7) Share and enjoy!
psad-7c4a910/deps/Bit-Vector/MANIFEST 0000664 0000000 0000000 00000001417 12071203757 0017044 0 ustar 00root root 0000000 0000000 Artistic.txt
BitVector.c
BitVector.h
CHANGES.txt
CREDITS.txt
GNU_GPL.txt
GNU_LGPL.txt
INSTALL.txt
MANIFEST
Makefile.PL
README.txt
ToolBox.h
Vector.pm
Vector.pod
Vector.xs
examples/SetObject.pl
examples/benchmk1.pl
examples/benchmk2.pl
examples/benchmk3.pl
examples/primes.pl
examples/test.c
lib/Bit/Vector/Overload.pm
lib/Bit/Vector/Overload.pod
lib/Bit/Vector/String.pm
lib/Bit/Vector/String.pod
t/00____version.t
t/01________new.t
t/02____destroy.t
t/03_operations.t
t/04__functions.t
t/05_____primes.t
t/06_____subset.t
t/07____compare.t
t/08_____resize.t
t/09_parameters.t
t/10__intervals.t
t/11______shift.t
t/12_____string.t
t/13__increment.t
t/14______empty.t
t/15________add.t
t/16___subtract.t
t/17________gcd.t
t/28__chunklist.t
t/30_overloaded.t
t/40__auxiliary.t
typemap
psad-7c4a910/deps/Bit-Vector/Makefile.PL 0000664 0000000 0000000 00000003674 12071203757 0017674 0 ustar 00root root 0000000 0000000 #!perl -w
###############################################################################
## ##
## Copyright (c) 1995 - 2004 by Steffen Beyer. ##
## All rights reserved. ##
## ##
## This package is free software; you can redistribute it ##
## and/or modify it under the same terms as Perl itself. ##
## ##
###############################################################################
use strict;
use ExtUtils::MakeMaker;
use Config;
WriteMakefile(
'NAME' => 'Bit::Vector',
'VERSION_FROM' => 'Vector.pm',
'PREREQ_PM' => { 'Carp::Clan' => 5.3 },
'OBJECT' => '$(O_FILES)',
# ($] >= 5.005 ?
# ('ABSTRACT' => 'Efficient base class implementing bit vectors',
# 'AUTHOR' => 'Steffen Beyer (sb@engelschall.com)') : ()),
# ($] >= 5.005 && $^O eq 'MSWin32' && $Config{archname} =~ /-object\b/i ?
# ('CAPI' => 'TRUE') : ()),
'dist' => { COMPRESS => "gzip -9", SUFFIX => "gz" }
);
my $patchlevel = $0;
$patchlevel =~ s![^/\\]*$!patchlevel.h!;
my $PATCHLEVEL = $Config{'PATCHLEVEL'} || $Config{'patchlevel'} || substr($],2,3);
my $SUBVERSION = $Config{'SUBVERSION'} || $Config{'subversion'} || substr($],5) || 0;
if (open(PATCHLEVEL, ">$patchlevel"))
{
print "Writing $patchlevel for $^X ($])\n";
printf PATCHLEVEL "#define PATCHLEVEL %d\n", $PATCHLEVEL;
printf PATCHLEVEL "#define SUBVERSION %d\n", $SUBVERSION;
close(PATCHLEVEL);
}
else
{
warn "Oops: Couldn't write file '$patchlevel': $!\n";
warn "However, you might succeed in building this module anyway;\n";
warn "Just try it!\n";
}
__END__
psad-7c4a910/deps/Bit-Vector/README.txt 0000664 0000000 0000000 00000033607 12071203757 0017417 0 ustar 00root root 0000000 0000000 =====================================
Package "Bit::Vector" Version 6.4
=====================================
This package is available for download either from my web site at
http://www.engelschall.com/u/sb/download/
or from any CPAN (= "Comprehensive Perl Archive Network") mirror server:
http://www.perl.com/CPAN/authors/id/S/ST/STBEY/
Abstract:
---------
Bit::Vector is an efficient C library which allows you to handle
bit vectors, sets (of integers), "big integer arithmetic" and
boolean matrices, all of arbitrary sizes.
The library is efficient (in terms of algorithmical complexity)
and therefore fast (in terms of execution speed) for instance
through the widespread use of divide-and-conquer algorithms.
The package also includes an object-oriented Perl module for
accessing the C library from Perl, and optionally features
overloaded operators for maximum ease of use.
The C library can nevertheless be used stand-alone, without Perl.
What's new in version 6.4:
--------------------------
+ Added compiler directives for C++.
+ Improved the method "Norm()".
+ Removed "Carp::Clan" from the distribution (available separately).
+ Added "Bit::Vector::String" for generic string import/export functions.
+ Added a new test file "t/40__auxiliary.t" for "Bit::Vector::String".
+ Fixed a bug in method "Copy()" concerning sign (MSB) extension.
Legal issues:
-------------
This package with all its parts is
Copyright (c) 1995 - 2004 by Steffen Beyer.
All rights reserved.
This package is free software; you can use, modify and redistribute
it under the same terms as Perl itself, i.e., under the terms of
the "Artistic License" or the "GNU General Public License".
The C library at the core of this Perl module can additionally
be used, modified and redistributed under the terms of the
"GNU Library General Public License".
Please refer to the files "Artistic.txt", "GNU_GPL.txt" and
"GNU_LGPL.txt" in this distribution, respectively, for details!
Prerequisites:
--------------
Perl version 5.000 or higher, and an ANSI C compiler. (!)
^^^^^^
Module "Carp::Clan" version 5.0 or higher.
Note that in order to compile Perl modules which contain
C (and/or XS) code (such as this one), you always HAVE
to use the very same compiler your Perl itself was compiled
with.
Many vendors nowadays ship their operating system already
comprising a precompiled version of Perl. Many times the
compilers used to compile this version of Perl are not
available to or not usually used by the users of these
operating systems.
In such cases building this module (or any other Perl
module containing C and/or XS code) will not work. You
will either have to get the compiler which was used to
compile Perl itself (see for example the section "Compiler:"
in the output of the command "perl -V"), or to build
your own Perl with the compiler of your choice (which
also allows you to take advantage of the various compile-
time switches Perl offers).
Note that Sun Solaris and Red Hat Linux frequently were
reported to suffer from this kind of problem.
Moreover, you usually cannot build any modules under
Windows 95/98 since the Win 95/98 command shell doesn't
support the "&&" operator. You will need the Windows NT
command shell ("cmd.exe") or the "4DOS" shell to be
installed on your Windows 95/98 system first. Note that
Windows NT and Windows 2000 are not affected and just
work fine. I don't know about Windows XP, however.
Note that ActiveState provides precompiled binaries of
this module for their Win32 port of Perl ("ActivePerl")
on their web site, which you should be able to install
simply by typing "ppm install Bit-Vector" in your MS-DOS
command shell (but note the "-" instead of "::" in the
package name!). This also works under Windows 95/98 (!).
If your firewall prevents "ppm" from downloading
this package, you can also download it manually from
http://www.activestate.com/ppmpackages/5.005/zips/ or
http://www.activestate.com/ppmpackages/5.6/zips/.
Follow the installation instructions included in
the "zip" archive.
Note to CPAN Testers:
---------------------
After completion, version 6.4 of this module has already
been tested successfully with the following configurations:
Perl 5.005_03 - FreeBSD 4.1.1-RELEASE (with "dlopen() relative paths" patch)
Perl 5.6.0 - FreeBSD 4.1.1-RELEASE
Perl 5.6.1 - FreeBSD 4.1.1-RELEASE
Perl 5.7.0 - FreeBSD 4.1.1-RELEASE
Perl 5.7.1 - FreeBSD 4.1.1-RELEASE
Perl 5.7.2 - FreeBSD 4.1.1-RELEASE
Perl 5.8.0 - FreeBSD 4.1.1-RELEASE
Perl 5.8.4 - FreeBSD 4.10-BETA
Perl 5.8.0 - Windows 2000 & MS VC++ 6.0 (native Perl build)
Installation:
-------------
Please see the file "INSTALL.txt" in this distribution for instructions
on how to install this package.
It is essential that you read this file since one of the special cases
described in it might apply to you, especially if you are running Perl
under Windows.
Changes over previous versions:
-------------------------------
Please refer to the file "CHANGES.txt" in this distribution for a more
detailed version history log.
Documentation:
--------------
The documentation of this package is included in POD format (= "Plain
Old Documentation") in the files with the extension ".pod" in this
distribution, the human-readable markup-language standard for Perl
documentation.
By building this package, this documentation will automatically be
converted into man pages, which will automatically be installed in
your Perl tree for further reference through the installation process,
where they can be accessed by the commands "man Bit::Vector" (Unix)
and "perldoc Bit::Vector" (Unix and Win32 alike), for example.
Available man pages:
Bit::Vector(3)
Bit::Vector::Overload(3)
Bit::Vector::String(3)
If Perl is not available on your system, you can also read the ".pod"
files
./Vector.pod
./lib/Bit/Vector/Overload.pod
./lib/Bit/Vector/String.pod
directly.
What does it do:
----------------
This package implements bit vectors of arbitrary size and provides efficient
methods for handling them.
This goes far beyond the built-in capabilities of Perl for handling bit
vectors (compare with the method list below!).
Moreover, the C core of this package can be used "stand-alone" in other
C applications; Perl is not necessarily required.
The main module of this package is intended to serve as a base class for
other applications or application classes, such as implementing sets or
performing big integer arithmetic.
All methods are implemented in C internally for maximum performance.
An add-on module (named "Bit::Vector::Overload") provides overloaded
arithmetic and relational operators for maximum ease of use (Perl only).
Note that there is (of course) a little speed penalty to pay for
overloaded operators. If speed is crucial, use the "Bit::Vector"
module alone!
Another module, "Bit::Vector::String", offers additional methods
for generic string export and import (also Perl only).
This package is useful for a large range of different tasks:
- For example for implementing sets and performing set operations
(like union, difference, intersection, complement, check for subset
relationship etc.),
- as a basis for many efficient algorithms, for instance the
"Sieve of Erathostenes" (for calculating prime numbers),
(The complexities of the methods in this package are usually either
O(1) or O(n/b), where "b" is the number of bits in a machine word
on your system.)
- for shift registers of arbitrary length (for example for cyclic
redundancy checksums),
- to calculate "look-ahead", "first" and "follow" character sets
for parsers and compiler-compilers,
- for graph algorithms,
- for efficient storage and retrieval of status information,
- for performing text synthesis ruled by boolean expressions,
- for "big integer" arithmetic with arbitrarily large integers,
- for manipulations of chunks of bits of arbitrary size,
- for bitwise processing of audio CD wave files,
- to convert formats of data files,
and more.
(A number of example applications is available from my web site at
http://www.engelschall.com/u/sb/download/.)
A large number of import/export methods allow you to access individual
bits, contiguous ranges of bits, machine words, arbitrary chunks of
bits, lists (arrays) of chunks of bits or machine words and a whole
bit vector at once (for instance for blockwrite/-read to and from
a file).
You can also import and export the contents of a bit vector in binary,
hexadecimal and decimal representation as well as ".newsrc" style
enumerations.
Note that this package is specifically designed for efficiency, which is
also the reason why its methods are implemented in C.
To further increase execution speed, the package doesn't use bytes as its
basic storage unit, but rather uses machine words, assuming that a machine
word is the most efficiently handled size of all scalar types on all
machines (that's what the ANSI C standard proposes and assumes anyway).
In order to achieve this, it automatically determines the number of bits
in a machine word on your system and then adjusts its internal configuration
constants accordingly.
The greater the size of this basic storage unit, the better the complexity
(= execution speed) of the methods in this package, but also the greater the
average waste of unused bits in the last word.
The range of available methods is exceptionally large for this kind of library;
in detail:
Version() Word_Bits() Long_Bits()
new() new_Hex() new_Bin()
new_Dec() new_Enum() Shadow()
Clone() Concat() Concat_List()
Size() Resize() Copy()
Empty() Fill() Flip()
Primes() Reverse() Interval_Empty()
Interval_Fill() Interval_Flip() Interval_Reverse()
Interval_Scan_inc() Interval_Scan_dec() Interval_Copy()
Interval_Substitute() is_empty() is_full()
equal() Lexicompare() Compare()
to_Hex() from_Hex() to_Bin()
from_Bin() to_Dec() from_Dec()
to_Enum() from_Enum() Bit_Off()
Bit_On() bit_flip() bit_test()
Bit_Copy() LSB() MSB()
lsb() msb() rotate_left()
rotate_right() shift_left() shift_right()
Move_Left() Move_Right() Insert()
Delete() increment() decrement()
inc() dec() add()
subtract() Negate() Absolute()
Sign() Multiply() Divide()
GCD() Power() Block_Store()
Block_Read() Word_Size() Word_Store()
Word_Read() Word_List_Store() Word_List_Read()
Word_Insert() Word_Delete() Chunk_Store()
Chunk_Read() Chunk_List_Store() Chunk_List_Read()
Index_List_Remove() Index_List_Store() Index_List_Read()
Union() Intersection() Difference()
ExclusiveOr() Complement() subset()
Norm() Min() Max()
Multiplication() Product() Closure()
Transpose()
Note to C developers:
---------------------
Note again that the C library at the core of this module can also be
used stand-alone (i.e., it contains no inter-dependencies whatsoever
with Perl).
The library itself consists of three files: "BitVector.c", "BitVector.h"
and "ToolBox.h".
Just compile "BitVector.c" (which automatically includes "ToolBox.h")
and link the resulting output file "BitVector.o" with your application,
which in turn should include "ToolBox.h" and "BitVector.h" (in this order).
Example applications:
---------------------
See the module "Set::IntRange" for an easy-to-use module for sets
of integers within arbitrary ranges.
See the module "Math::MatrixBool" for an efficient implementation
of boolean matrices and boolean matrix operations.
(Both modules are also available from my web site at
http://www.engelschall.com/u/sb/download/ or any CPAN server.)
See the file "SetObject.pl" in the "examples" subdirectory of this
distribution for a way to emulate the "Set::Object" module from CPAN
using "Bit::Vector" - this is a way to perform set operations on sets
of arbitrary objects (any Perl objects or Perl data structures you want!).
An application relying crucially on this "Bit::Vector" module is "Slice",
a tool for generating different document versions out of a single
master file, ruled by boolean expressions ("include english version
of text plus examples but not ...").
(See also http://www.engelschall.com/sw/slice/.)
This tool is itself part of another tool, "Website META Language" ("WML"),
which allows you to generate and maintain large web sites.
Among many other features, it allows you to define your own HTML tags which
will be expanded either at generation or at run time, depending on your
choice.
(See also http://www.engelschall.com/sw/wml/.)
Both tools are written by Ralf S. Engelschall.
Credits:
--------
Please refer to the file "CREDITS.txt" in this distribution for a list
of contributors.
Author's note:
--------------
If you have any questions, suggestions or need any assistance, please
let me know!
Please do send feedback, this is essential for improving this module
according to your needs!
I hope you will find this module useful. Enjoy!
Yours,
--
Steffen Beyer http://www.engelschall.com/u/sb/
"There is enough for the need of everyone in this world, but not
for the greed of everyone." - Mohandas Karamchand "Mahatma" Gandhi
psad-7c4a910/deps/Bit-Vector/ToolBox.h 0000664 0000000 0000000 00000021235 12071203757 0017452 0 ustar 00root root 0000000 0000000 #ifndef MODULE_TOOLBOX
#define MODULE_TOOLBOX
#ifdef __cplusplus
extern "C"
{
#endif
/*****************************************************************************/
/* MODULE NAME: ToolBox.h MODULE TYPE: (dat) */
/*****************************************************************************/
/* MODULE IMPORTS: */
/*****************************************************************************/
/*****************************************************************************/
/* MODULE INTERFACE: */
/*****************************************************************************/
/*****************************************************************************/
/* MODULE RESOURCES: */
/*****************************************************************************/
/*****************************************************************************/
/* NOTE: The type names that have been chosen here are somewhat weird on */
/* purpose, in order to avoid name clashes with system header files */
/* and your own application(s) which might - directly or indirectly - */
/* include this definitions file. */
/*****************************************************************************/
typedef unsigned char N_char;
typedef unsigned char N_byte;
typedef unsigned short N_short;
typedef unsigned short N_shortword;
typedef unsigned int N_int;
typedef unsigned int N_word;
typedef unsigned long N_long;
typedef unsigned long N_longword;
/* Mnemonic 1: The natural numbers, N = { 0, 1, 2, 3, ... } */
/* Mnemonic 2: Nnnn = u_N_signed, _N_ot signed */
typedef signed char Z_char;
typedef signed char Z_byte;
typedef signed short Z_short;
typedef signed short Z_shortword;
typedef signed int Z_int;
typedef signed int Z_word;
typedef signed long Z_long;
typedef signed long Z_longword;
/* Mnemonic 1: The whole numbers, Z = { 0, -1, 1, -2, 2, -3, 3, ... } */
/* Mnemonic 2: Zzzz = Ssss_igned */
typedef void *voidptr;
typedef N_char *charptr;
typedef N_byte *byteptr;
typedef N_short *shortptr;
typedef N_shortword *shortwordptr;
typedef N_int *intptr;
typedef N_word *wordptr;
typedef N_long *longptr;
typedef N_longword *longwordptr;
typedef N_char *N_charptr;
typedef N_byte *N_byteptr;
typedef N_short *N_shortptr;
typedef N_shortword *N_shortwordptr;
typedef N_int *N_intptr;
typedef N_word *N_wordptr;
typedef N_long *N_longptr;
typedef N_longword *N_longwordptr;
typedef Z_char *Z_charptr;
typedef Z_byte *Z_byteptr;
typedef Z_short *Z_shortptr;
typedef Z_shortword *Z_shortwordptr;
typedef Z_int *Z_intptr;
typedef Z_word *Z_wordptr;
typedef Z_long *Z_longptr;
typedef Z_longword *Z_longwordptr;
#undef FALSE
#define FALSE (0!=0)
#undef TRUE
#define TRUE (0==0)
#ifdef __cplusplus
typedef bool boolean;
#else
#ifdef MACOS_TRADITIONAL
#define boolean Boolean
#else
typedef enum { false = FALSE, true = TRUE } boolean;
#endif
#endif
#define and && /* logical (boolean) operators: lower case */
#define or ||
#define not !
#define AND & /* binary (bitwise) operators: UPPER CASE */
#define OR |
#define XOR ^
#define NOT ~
#define SHL <<
#define SHR >>
#ifdef ENABLE_MODULO
#define mod % /* arithmetic operators */
#endif
#define blockdef(name,size) unsigned char name[size]
#define blocktypedef(name,size) typedef unsigned char name[size]
/*****************************************************************************/
/* MODULE IMPLEMENTATION: */
/*****************************************************************************/
/*****************************************************************************/
/* VERSION: 5.5 */
/*****************************************************************************/
/* VERSION HISTORY: */
/*****************************************************************************/
/* */
/* Version 5.5 03.10.04 Added compiler directives for C++. */
/* Version 5.4 08.09.02 Added conditional changes for MacOS/MacPerl. */
/* Version 5.3 12.05.98 Completed history. */
/* Version 5.0 01.03.98 "Definitions.h" -> "ToolBox.h". */
/* Version 4.0 24.03.97 "lib_defs.h" -> "Definitions.h". */
/* Version 3.0 16.02.97 Changed frames from 40 to 80 columns. */
/* Version 2.0 30.11.96 byte -> base etc. */
/* Version 1.2a 21.11.95 unchar -> N_char etc. Added MS-DOS specifics. */
/* Version 1.1 18.11.95 uchar -> unchar etc. */
/* Version 1.01 16.11.95 Removed MS-DOS specifics. */
/* Version 1.0 12.11.95 First version under UNIX (with Perl modules). */
/* Version 0.9 01.11.93 First version under MS-DOS. */
/* */
/*****************************************************************************/
/* AUTHOR: */
/*****************************************************************************/
/* */
/* Steffen Beyer */
/* mailto:sb@engelschall.com */
/* http://www.engelschall.com/u/sb/download/ */
/* */
/*****************************************************************************/
/* COPYRIGHT: */
/*****************************************************************************/
/* */
/* Copyright (c) 1995 - 2004 by Steffen Beyer. */
/* All rights reserved. */
/* */
/*****************************************************************************/
/* LICENSE: */
/*****************************************************************************/
/* */
/* This library is free software; you can redistribute it and/or */
/* modify it under the terms of the GNU Library General Public */
/* License as published by the Free Software Foundation; either */
/* version 2 of the License, or (at your option) any later version. */
/* */
/* This library is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
/* Library General Public License for more details. */
/* */
/* You should have received a copy of the GNU Library General Public */
/* License along with this library; if not, write to the */
/* Free Software Foundation, Inc., */
/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* or download a copy from ftp://ftp.gnu.org/pub/gnu/COPYING.LIB-2.0 */
/* */
/*****************************************************************************/
#ifdef __cplusplus
}
#endif
#endif
psad-7c4a910/deps/Bit-Vector/VERSION 0000664 0000000 0000000 00000000004 12071203757 0016752 0 ustar 00root root 0000000 0000000 6.4
psad-7c4a910/deps/Bit-Vector/Vector.pm 0000664 0000000 0000000 00000001732 12071203757 0017513 0 ustar 00root root 0000000 0000000
###############################################################################
## ##
## Copyright (c) 1995 - 2004 by Steffen Beyer. ##
## All rights reserved. ##
## ##
## This package is free software; you can redistribute it ##
## and/or modify it under the same terms as Perl itself. ##
## ##
###############################################################################
package Bit::Vector;
use strict;
use vars qw(@ISA @EXPORT @EXPORT_OK $VERSION @CONFIG);
require Exporter;
require DynaLoader;
@ISA = qw(Exporter DynaLoader);
@EXPORT = qw();
@EXPORT_OK = qw();
$VERSION = '6.4';
bootstrap Bit::Vector $VERSION;
1;
__END__
psad-7c4a910/deps/Bit-Vector/Vector.pod 0000664 0000000 0000000 00000311157 12071203757 0017666 0 ustar 00root root 0000000 0000000
=head1 NAME
Bit::Vector - Efficient bit vector, set of integers and "big int" math library
=head1 SYNOPSIS
=head2 OVERLOADED OPERATORS
See L.
=head2 MORE STRING IMPORT/EXPORT
See L.
=head2 CLASS METHODS
Version
$version = Bit::Vector->Version();
Word_Bits
$bits = Bit::Vector->Word_Bits(); # bits in a machine word
Long_Bits
$bits = Bit::Vector->Long_Bits(); # bits in an unsigned long
new
$vector = Bit::Vector->new($bits); # bit vector constructor
@veclist = Bit::Vector->new($bits,$count);
new_Hex
$vector = Bit::Vector->new_Hex($bits,$string);
new_Bin
$vector = Bit::Vector->new_Bin($bits,$string);
new_Dec
$vector = Bit::Vector->new_Dec($bits,$string);
new_Enum
$vector = Bit::Vector->new_Enum($bits,$string);
Concat_List
$vector = Bit::Vector->Concat_List(@vectors);
=head2 OBJECT METHODS
new
$vec2 = $vec1->new($bits); # alternative call of constructor
@veclist = $vec->new($bits,$count);
Shadow
$vec2 = $vec1->Shadow(); # new vector, same size but empty
Clone
$vec2 = $vec1->Clone(); # new vector, exact duplicate
Concat
$vector = $vec1->Concat($vec2);
Concat_List
$vector = $vec1->Concat_List($vec2,$vec3,...);
Size
$bits = $vector->Size();
Resize
$vector->Resize($bits);
$vector->Resize($vector->Size()+5);
$vector->Resize($vector->Size()-5);
Copy
$vec2->Copy($vec1);
Empty
$vector->Empty();
Fill
$vector->Fill();
Flip
$vector->Flip();
Primes
$vector->Primes(); # Sieve of Erathostenes
Reverse
$vec2->Reverse($vec1);
Interval_Empty
$vector->Interval_Empty($min,$max);
Interval_Fill
$vector->Interval_Fill($min,$max);
Interval_Flip
$vector->Interval_Flip($min,$max);
Interval_Reverse
$vector->Interval_Reverse($min,$max);
Interval_Scan_inc
if (($min,$max) = $vector->Interval_Scan_inc($start))
Interval_Scan_dec
if (($min,$max) = $vector->Interval_Scan_dec($start))
Interval_Copy
$vec2->Interval_Copy($vec1,$offset2,$offset1,$length);
Interval_Substitute
$vec2->Interval_Substitute($vec1,$off2,$len2,$off1,$len1);
is_empty
if ($vector->is_empty())
is_full
if ($vector->is_full())
equal
if ($vec1->equal($vec2))
Lexicompare (unsigned)
if ($vec1->Lexicompare($vec2) == 0)
if ($vec1->Lexicompare($vec2) != 0)
if ($vec1->Lexicompare($vec2) < 0)
if ($vec1->Lexicompare($vec2) <= 0)
if ($vec1->Lexicompare($vec2) > 0)
if ($vec1->Lexicompare($vec2) >= 0)
Compare (signed)
if ($vec1->Compare($vec2) == 0)
if ($vec1->Compare($vec2) != 0)
if ($vec1->Compare($vec2) < 0)
if ($vec1->Compare($vec2) <= 0)
if ($vec1->Compare($vec2) > 0)
if ($vec1->Compare($vec2) >= 0)
to_Hex
$string = $vector->to_Hex();
from_Hex
$vector->from_Hex($string);
to_Bin
$string = $vector->to_Bin();
from_Bin
$vector->from_Bin($string);
to_Dec
$string = $vector->to_Dec();
from_Dec
$vector->from_Dec($string);
to_Enum
$string = $vector->to_Enum(); # e.g. "2,3,5-7,11,13-19"
from_Enum
$vector->from_Enum($string);
Bit_Off
$vector->Bit_Off($index);
Bit_On
$vector->Bit_On($index);
bit_flip
$bit = $vector->bit_flip($index);
bit_test
contains
$bit = $vector->bit_test($index);
$bit = $vector->contains($index);
if ($vector->bit_test($index))
if ($vector->contains($index))
Bit_Copy
$vector->Bit_Copy($index,$bit);
LSB (least significant bit)
$vector->LSB($bit);
MSB (most significant bit)
$vector->MSB($bit);
lsb (least significant bit)
$bit = $vector->lsb();
msb (most significant bit)
$bit = $vector->msb();
rotate_left
$carry = $vector->rotate_left();
rotate_right
$carry = $vector->rotate_right();
shift_left
$carry = $vector->shift_left($carry);
shift_right
$carry = $vector->shift_right($carry);
Move_Left
$vector->Move_Left($bits); # shift left "$bits" positions
Move_Right
$vector->Move_Right($bits); # shift right "$bits" positions
Insert
$vector->Insert($offset,$bits);
Delete
$vector->Delete($offset,$bits);
increment
$carry = $vector->increment();
decrement
$carry = $vector->decrement();
inc
$overflow = $vec2->inc($vec1);
dec
$overflow = $vec2->dec($vec1);
add
$carry = $vec3->add($vec1,$vec2,$carry);
($carry,$overflow) = $vec3->add($vec1,$vec2,$carry);
subtract
$carry = $vec3->subtract($vec1,$vec2,$carry);
($carry,$overflow) = $vec3->subtract($vec1,$vec2,$carry);
Neg
Negate
$vec2->Neg($vec1);
$vec2->Negate($vec1);
Abs
Absolute
$vec2->Abs($vec1);
$vec2->Absolute($vec1);
Sign
if ($vector->Sign() == 0)
if ($vector->Sign() != 0)
if ($vector->Sign() < 0)
if ($vector->Sign() <= 0)
if ($vector->Sign() > 0)
if ($vector->Sign() >= 0)
Multiply
$vec3->Multiply($vec1,$vec2);
Divide
$quot->Divide($vec1,$vec2,$rest);
GCD (Greatest Common Divisor)
$vecgcd->GCD($veca,$vecb);
$vecgcd->GCD($vecx,$vecy,$veca,$vecb);
Power
$vec3->Power($vec1,$vec2);
Block_Store
$vector->Block_Store($buffer);
Block_Read
$buffer = $vector->Block_Read();
Word_Size
$size = $vector->Word_Size(); # number of words in "$vector"
Word_Store
$vector->Word_Store($offset,$word);
Word_Read
$word = $vector->Word_Read($offset);
Word_List_Store
$vector->Word_List_Store(@words);
Word_List_Read
@words = $vector->Word_List_Read();
Word_Insert
$vector->Word_Insert($offset,$count);
Word_Delete
$vector->Word_Delete($offset,$count);
Chunk_Store
$vector->Chunk_Store($chunksize,$offset,$chunk);
Chunk_Read
$chunk = $vector->Chunk_Read($chunksize,$offset);
Chunk_List_Store
$vector->Chunk_List_Store($chunksize,@chunks);
Chunk_List_Read
@chunks = $vector->Chunk_List_Read($chunksize);
Index_List_Remove
$vector->Index_List_Remove(@indices);
Index_List_Store
$vector->Index_List_Store(@indices);
Index_List_Read
@indices = $vector->Index_List_Read();
Or
Union
$vec3->Or($vec1,$vec2);
$set3->Union($set1,$set2);
And
Intersection
$vec3->And($vec1,$vec2);
$set3->Intersection($set1,$set2);
AndNot
Difference
$vec3->AndNot($vec1,$vec2);
$set3->Difference($set1,$set2);
Xor
ExclusiveOr
$vec3->Xor($vec1,$vec2);
$set3->ExclusiveOr($set1,$set2);
Not
Complement
$vec2->Not($vec1);
$set2->Complement($set1);
subset
if ($set1->subset($set2)) # true if $set1 is subset of $set2
Norm
$norm = $set->Norm();
$norm = $set->Norm2();
$norm = $set->Norm3();
Min
$min = $set->Min();
Max
$max = $set->Max();
Multiplication
$matrix3->Multiplication($rows3,$cols3,
$matrix1,$rows1,$cols1,
$matrix2,$rows2,$cols2);
Product
$matrix3->Product($rows3,$cols3,
$matrix1,$rows1,$cols1,
$matrix2,$rows2,$cols2);
Closure
$matrix->Closure($rows,$cols);
Transpose
$matrix2->Transpose($rows2,$cols2,$matrix1,$rows1,$cols1);
=head1 IMPORTANT NOTES
=over 2
=item *
Method naming conventions
Method names completely in lower case indicate a boolean return value.
(Except for the bit vector constructor method "C", of course.)
=item *
Boolean values
Boolean values in this module are always a numeric zero ("C<0>") for
"false" and a numeric one ("C<1>") for "true".
=item *
Negative numbers
All numeric input parameters passed to any of the methods in this module
are regarded as being B (as opposed to the contents of the
bit vectors themselves, which are usually considered to be B).
As a consequence, whenever you pass a negative number as an argument to
some method of this module, it will be treated as a (usually very large)
positive number due to its internal two's complement binary representation,
usually resulting in an "index out of range" error message and program
abortion.
=item *
Bit order
Note that bit vectors are stored least order bit and least order word first
internally.
I.e., bit #0 of any given bit vector corresponds to bit #0 of word #0 in the
array of machine words representing the bit vector.
(Where word #0 comes first in memory, i.e., it is stored at the least memory
address in the allocated block of memory holding the given bit vector.)
Note however that machine words can be stored least order byte first or last,
depending on your system's implementation.
When you are exporting or importing a whole bit vector at once using the
methods "C" and "C" (the only time in this
module where this could make any difference), however, a conversion to and
from "least order byte first" order is automatically supplied.
In other words, what "C" provides and what "C"
expects is always in "least order byte first" order, regardless of the order
in which words are stored internally on your machine.
This is to make sure that what you export on one machine using "C"
can always be read in correctly with "C" on a different machine.
Note further that whenever bit vectors are converted to and from (binary or
hexadecimal) strings, the B bit is always the B
one, and the B bit is always the B bit.
This is because in our western culture, numbers are always represented in this
way (least significant to most significant digits go from right to left).
Of course this requires an internal reversion of order, which the corresponding
conversion methods perform automatically (without any additional overhead, it's
just a matter of starting the internal loop at the bottom or the top end).
=item *
"Word" related methods
Note that all methods whose names begin with "C" are
B!
They depend on the size (number of bits) of an "unsigned int" (C type) on
your machine.
Therefore, you should only use these methods if you are B
that portability of your code is not an issue!
Note that you can use arbitrarily large chunks (i.e., fragments of bit vectors)
of up to 32 bits B using the methods whose names begin with
"C".
=item *
Chunk sizes
Note that legal chunk sizes for all methods whose names begin with "C"
range from "C<1>" to "CLong_Bits();>" bits ("C<0>" is B
allowed!).
In order to make your programs portable, however, you shouldn't use chunk sizes
larger than 32 bits, since this is the minimum size of an "unsigned long"
(C type) on all systems, as prescribed by S.
=item *
Matching sizes
In general, for methods involving several bit vectors at the same time, all
bit vector arguments must have identical sizes (number of bits), or a fatal
"size mismatch" error will occur.
Exceptions from this rule are the methods "C", "C",
"C", "C" and "C", where no
conditions at all are imposed on the size of their bit vector arguments.
In method "C", all three bit vector arguments must in principle
obey the rule of matching sizes, but the bit vector in which the result of
the multiplication is to be stored may be larger than the two bit vector
arguments containing the factors for the multiplication.
In method "C", the bit vector for the result must be the same
size or greater than the base of the exponentiation term. The exponent
can be any size.
=item *
Index ranges
All indices for any given bits must lie between "C<0>" and
"CSize()-1>", or a fatal "index out of range"
error will occur.
=back
=head1 DESCRIPTION
=head2 OVERLOADED OPERATORS
See L.
=head2 MORE STRING IMPORT/EXPORT
See L.
=head2 CLASS METHODS
=over 2
=item *
CVersion();>
Returns the current version number of this module.
=item *
CWord_Bits();>
Returns the number of bits of an "unsigned int" (C type)
on your machine.
(An "unsigned int" is also called a "machine word",
hence the name of this method.)
=item *
CLong_Bits();>
Returns the number of bits of an "unsigned long" (C type)
on your machine.
=item *
Cnew($bits);>
This is the bit vector constructor method.
Call this method to create a new bit vector containing "C"
bits (with indices ranging from "C<0>" to "C").
Note that - in contrast to previous versions - bit vectors
of length zero (i.e., with C) are permitted now.
The method returns a reference to the newly created bit vector.
A new bit vector is always initialized so that all bits are cleared
(turned off).
An exception will be raised if the method is unable to allocate the
necessary memory.
Note that if you specify a negative number for "C" it will be
interpreted as a large positive number due to its internal two's
complement binary representation.
In such a case, the bit vector constructor method will obediently attempt
to create a bit vector of that size, probably resulting in an exception,
as explained above.
=item *
Cnew($bits,$count);>
You can also create more than one bit vector at a time if you specify the
optional second parameter "C".
The method returns a list of "C" bit vectors which all have the
same number of bits "C" (and which are all initialized, i.e.,
all bits are cleared).
If "C" is zero, an empty list is returned.
If "C" is zero, a list of null-sized bit vectors is returned.
Note again that if you specify a negative number for "C" it will
be interpreted as a large positive number due to its internal two's
complement binary representation.
In such a case, the bit vector constructor method will obediently attempt
to create that many bit vectors, probably resulting in an exception ("out
of memory").
=item *
Cnew_Hex($bits,$string);>
This method is an alternative constructor which allows you to create
a new bit vector object (with "C" bits) and to initialize it
all in one go.
The method internally first calls the bit vector constructor method
"C" and then passes the given string to the method "C".
However, this method is more efficient than performing these two steps
separately: First because in this method, the memory area occupied by
the new bit vector is not initialized to zeros (which is pointless in
this case), and second because it saves you from the associated overhead
of one additional method invocation.
An exception will be raised if the necessary memory cannot be allocated
(see the description of the method "C" immediately above for
possible causes) or if the given string cannot be converted successfully
(see the description of the method "C" further below for
details).
In the latter case, the memory occupied by the new bit vector is
released first (i.e., "free"d) before the exception is actually
raised.
=item *
Cnew_Bin($bits,$string);>
This method is an alternative constructor which allows you to create
a new bit vector object (with "C" bits) and to initialize it
all in one go.
The method internally first calls the bit vector constructor method
"C" and then passes the given string to the method "C".
However, this method is more efficient than performing these two steps
separately: First because in this method, the memory area occupied by
the new bit vector is not initialized to zeros (which is pointless in
this case), and second because it saves you from the associated overhead
of one additional method invocation.
An exception will be raised if the necessary memory cannot be allocated
(see the description of the method "C" above for possible causes)
or if the given string cannot be converted successfully (see the
description of the method "C" further below for details).
In the latter case, the memory occupied by the new bit vector is
released first (i.e., "free"d) before the exception is actually
raised.
=item *
Cnew_Dec($bits,$string);>
This method is an alternative constructor which allows you to create
a new bit vector object (with "C" bits) and to initialize it
all in one go.
The method internally first calls the bit vector constructor method
"C" and then passes the given string to the method "C".
However, this method is more efficient than performing these two steps
separately: First because in this method, "C" does not initialize
the memory area occupied by the new bit vector with zeros (which is
pointless in this case, because "C" will do it anyway),
and second because it saves you from the associated overhead of one
additional method invocation.
An exception will be raised if the necessary memory cannot be allocated
(see the description of the method "C" above for possible causes)
or if the given string cannot be converted successfully (see the
description of the method "C" further below for details).
In the latter case, the memory occupied by the new bit vector is
released first (i.e., "free"d) before the exception is actually
raised.
=item *
Cnew_Enum($bits,$string);>
This method is an alternative constructor which allows you to create
a new bit vector object (with "C" bits) and to initialize it
all in one go.
The method internally first calls the bit vector constructor method
"C" and then passes the given string to the method "C".
However, this method is more efficient than performing these two steps
separately: First because in this method, "C" does not initialize
the memory area occupied by the new bit vector with zeros (which is
pointless in this case, because "C" will do it anyway),
and second because it saves you from the associated overhead of one
additional method invocation.
An exception will be raised if the necessary memory cannot be allocated
(see the description of the method "C" above for possible causes)
or if the given string cannot be converted successfully (see the
description of the method "C" further below for details).
In the latter case, the memory occupied by the new bit vector is
released first (i.e., "free"d) before the exception is actually
raised.
=item *
CConcat_List(@vectors);>
This method creates a new vector containing all bit vectors from the
argument list in concatenated form.
The argument list may contain any number of arguments (including
zero); the only condition is that all arguments must be bit vectors.
There is no condition concerning the length (in number of bits) of
these arguments.
The vectors from the argument list are not changed in any way.
If the argument list is empty or if all arguments have length zero,
the resulting bit vector will also have length zero.
Note that the B bit vector from the argument list will
become the B significant part of the resulting bit vector,
and the B bit vector from the argument list will
become the B significant part of the resulting bit vector.
=back
=head2 OBJECT METHODS
=over 2
=item *
Cnew($bits);>
Cnew($bits);>
This is an alternative way of calling the bit vector constructor method.
Vector "C" (or "C") is not affected by this, it just serves
as an anchor for the method invocation mechanism.
In fact B class methods in this module can be called this way,
even though this is probably considered to be "politically incorrect"
by OO ("object-orientation") aficionados. ;-)
So even if you are too lazy to type "C>" instead of
"C>" (and even though laziness is - allegedly - a programmer's
virtue C), maybe it is better not to use this feature if you don't
want to get booed at. ;-)
=item *
CShadow();>
Creates a B bit vector "C" of the B as "C"
but which is B.
Just like a shadow that has the same shape as the object it
originates from, but is flat and has no volume, i.e., contains
nothing.
=item *
CClone();>
Creates a B bit vector "C" of the B as "C"
which is an B of "C".
=item *
CConcat($vec2);>
This method returns a new bit vector object which is the result of the
concatenation of the contents of "C" and "C".
Note that the contents of "C" become the B significant part
of the resulting bit vector, and "C" the B significant part.
If both bit vector arguments have length zero, the resulting bit vector
will also have length zero.
=item *
CConcat_List($vec2,$vec3,...);>
This is an alternative way of calling this (class) method as an
object method.
The method returns a new bit vector object which is the result of
the concatenation of the contents of C
See the section "class methods" above for a detailed description of
this method.
Note that the argument list may be empty and that all arguments
must be bit vectors if it isn't.
=item *
CSize();>
Returns the size (number of bits) the given vector was created with
(or "C"d to).
=item *
CResize($bits);>
Changes the size of the given vector to the specified number of bits.
This method allows you to change the size of an existing bit vector,
preserving as many bits from the old vector as will fit into the
new one (i.e., all bits with indices smaller than the minimum of the
sizes of both vectors, old and new).
If the number of machine words needed to store the new vector is smaller
than or equal to the number of words needed to store the old vector, the
memory allocated for the old vector is reused for the new one, and only
the relevant book-keeping information is adjusted accordingly.
This means that even if the number of bits increases, new memory is not
necessarily being allocated (i.e., if the old and the new number of bits
fit into the same number of machine words).
If the number of machine words needed to store the new vector is greater
than the number of words needed to store the old vector, new memory is
allocated for the new vector, the old vector is copied to the new one,
the remaining bits in the new vector are cleared (turned off) and the old
vector is deleted, i.e., the memory that was allocated for it is released.
(An exception will be raised if the method is unable to allocate the
necessary memory for the new vector.)
As a consequence, if you decrease the size of a given vector so that
it will use fewer machine words, and increase it again later so that it
will use more words than immediately before but still less than the
original vector, new memory will be allocated anyway because the
information about the size of the original vector is lost whenever
you resize it.
Note also that if you specify a negative number for "C" it will
be interpreted as a large positive number due to its internal two's
complement binary representation.
In such a case, "Resize()" will obediently attempt to create a bit
vector of that size, probably resulting in an exception, as explained
above.
Finally, note that - in contrast to previous versions - resizing a bit
vector to a size of zero bits (length zero) is now permitted.
=item *
CCopy($vec1);>
Copies the contents of bit vector "C" to bit vector "C".
The previous contents of bit vector "C" get overwritten, i.e.,
are lost.
Both vectors must exist beforehand, i.e., this method does not B
any new bit vector object.
The two vectors may be of any size.
If the source bit vector is larger than the target, this method will copy
as much of the least significant bits of the source vector as will fit into
the target vector, thereby discarding any extraneous most significant bits.
BEWARE that this causes a brutal cutoff in the middle of your data, and it
will also leave you with an almost unpredictable sign if subsequently the
number in the target vector is going to be interpreted as a number! (You
have been warned!)
If the target bit vector is larger than the source, this method fills up
the remaining most significant bits in the target bit vector with either
0's or 1's, depending on the sign (= the most significant bit) of the
source bit vector. This is also known as "sign extension".
This makes it possible to copy numbers from a smaller bit vector into
a larger one while preserving the number's absolute value as well as
its sign (due to the two's complement binary representation of numbers).
=item *
CEmpty();>
Clears all bits in the given vector.
=item *
CFill();>
Sets all bits in the given vector.
=item *
CFlip();>
Flips (i.e., complements) all bits in the given vector.
=item *
CPrimes();>
Clears the given bit vector and sets all bits whose
indices are prime numbers.
This method uses the algorithm known as the "Sieve of
Erathostenes" internally.
=item *
CReverse($vec1);>
This method copies the given vector "C" to
the vector "C", thereby reversing the order
of all bits.
I.e., the least significant bit of "C" becomes the
most significant bit of "C", whereas the most
significant bit of "C" becomes the least
significant bit of "C", and so forth
for all bits in between.
Note that in-place processing is also possible, i.e.,
"C" and "C" may be identical.
(Internally, this is the same as
CInterval_Reverse(0,$vec1-ESize()-1);>.)
=item *
CInterval_Empty($min,$max);>
Clears all bits in the interval C (including both limits)
in the given vector.
"C" and "C" may have the same value; this is the same
as clearing a single bit with "C" (but less efficient).
Note that CInterval_Empty(0,$vector-ESize()-1);>
is the same as CEmpty();> (but less efficient).
=item *
CInterval_Fill($min,$max);>
Sets all bits in the interval C (including both limits)
in the given vector.
"C" and "C" may have the same value; this is the same
as setting a single bit with "C" (but less efficient).
Note that CInterval_Fill(0,$vector-ESize()-1);>
is the same as CFill();> (but less efficient).
=item *
CInterval_Flip($min,$max);>
Flips (i.e., complements) all bits in the interval C
(including both limits) in the given vector.
"C" and "C" may have the same value; this is the same
as flipping a single bit with "C" (but less efficient).
Note that CInterval_Flip(0,$vector-ESize()-1);>
is the same as CFlip();> and
CComplement($vector);>
(but less efficient).
=item *
CInterval_Reverse($min,$max);>
Reverses the order of all bits in the interval C
(including both limits) in the given vector.
I.e., bits "C" and "C" swap places, and so forth
for all bits in between.
"C" and "C" may have the same value; this has no
effect whatsoever, though.
=item *
CInterval_Scan_inc($start))>
Returns the minimum and maximum indices of the next contiguous block
of set bits (i.e., bits in the "on" state).
The search starts at index "C" (i.e., C= "$start">)
and proceeds upwards (i.e., C= "$min">), thus repeatedly
increments the search pointer "C" (internally).
Note though that the contents of the variable (or scalar literal value)
"C" is B altered. I.e., you have to set it to the desired
value yourself prior to each call to "C" (see also
the example given below).
Actually, the bit vector is not searched bit by bit, but one machine
word at a time, in order to speed up execution (which means that this
method is quite efficient).
An empty list is returned if no such block can be found.
Note that a single set bit (surrounded by cleared bits) is a valid
block by this definition. In that case the return values for "C"
and "C" are the same.
Typical use:
$start = 0;
while (($start < $vector->Size()) &&
(($min,$max) = $vector->Interval_Scan_inc($start)))
{
$start = $max + 2;
# do something with $min and $max
}
=item *
CInterval_Scan_dec($start))>
Returns the minimum and maximum indices of the next contiguous block
of set bits (i.e., bits in the "on" state).
The search starts at index "C" (i.e., C= "$start">)
and proceeds downwards (i.e., C= "$max">), thus repeatedly
decrements the search pointer "C" (internally).
Note though that the contents of the variable (or scalar literal value)
"C" is B altered. I.e., you have to set it to the desired
value yourself prior to each call to "C" (see also
the example given below).
Actually, the bit vector is not searched bit by bit, but one machine
word at a time, in order to speed up execution (which means that this
method is quite efficient).
An empty list is returned if no such block can be found.
Note that a single set bit (surrounded by cleared bits) is a valid
block by this definition. In that case the return values for "C"
and "C" are the same.
Typical use:
$start = $vector->Size() - 1;
while (($start >= 0) &&
(($min,$max) = $vector->Interval_Scan_dec($start)))
{
$start = $min - 2;
# do something with $min and $max
}
=item *
CInterval_Copy($vec1,$offset2,$offset1,$length);>
This method allows you to copy a stretch of contiguous bits (starting
at any position "C" you choose, with a length of "C"
bits) from a given "source" bit vector "C" to another position
"C" in a "target" bit vector "C".
Note that the two bit vectors "C" and "C" do B
need to have the same (matching) size!
Consequently, any of the two terms "C" and
"C" (or both) may exceed the actual length
of its corresponding bit vector ("CSize()>" and
"CSize()>", respectively).
In such a case, the "C" parameter is automatically reduced
internally so that both terms above are bounded by the number of bits
of their corresponding bit vector.
This may even result in a length of zero, in which case nothing is
copied at all.
(Of course the value of the "C" parameter, supplied by you
in the initial method call, may also be zero right from the start!)
Note also that "C" and "C" must lie within the
range "C<0>" and, respectively, "CSize()-1>" or
"CSize()-1>", or a fatal "offset out of range" error
will occur.
Note further that "C" and "C" may be identical, i.e.,
you may copy a stretch of contiguous bits from one part of a given
bit vector to another part.
The source and the target interval may even overlap, in which case
the copying is automatically performed in ascending or descending
order (depending on the direction of the copy - downwards or upwards
in the bit vector, respectively) to handle this situation correctly,
i.e., so that no bits are being overwritten before they have been
copied themselves.
=item *
CInterval_Substitute($vec1,$off2,$len2,$off1,$len1);>
This method is (roughly) the same for bit vectors (i.e., arrays
of booleans) as what the "splice" function in Perl is for lists
(i.e., arrays of scalars).
(See L for more details about this function.)
The method allows you to substitute a stretch of contiguous bits
(defined by a position (offset) "C" and a length of "C"
bits) from a given "source" bit vector "C" for a different
stretch of contiguous bits (defined by a position (offset) "C"
and a length of "C" bits) in another, "target" bit vector
"C".
Note that the two bit vectors "C" and "C" do B
need to have the same (matching) size!
Note further that "C" and "C" must lie within the
range "C<0>" and, respectively, "CSize()>" or
"CSize()>", or a fatal "offset out of range" error
will occur.
Alert readers will have noticed that these upper limits are B
"CSize()-1>" and "CSize()-1>", as they would
be for any other method in this module, but that these offsets may
actually point to one position B of the corresponding
bit vector.
This is necessary in order to make it possible to B a given
stretch of bits to the target bit vector instead of B
something in it.
For reasons of symmetry and generality, the same applies to the offset
in the source bit vector, even though such an offset (one position past
the end of the bit vector) does not serve any practical purpose there
(but does not cause any harm either).
(Actually this saves you from the need of testing for this special case,
in certain circumstances.)
Note that whenever the term "C" exceeds the size
"CSize()>" of bit vector "C" (or if "C"
exceeds "CSize()>"), the corresponding length ("C"
or "C", respectively) is automatically reduced internally
so that "C= $vec1-ESize()>" (and
"C= $vec2-ESize()>") holds.
(Note that this does B alter the intended result, even though
this may seem counter-intuitive at first!)
This may even result in a length ("C" or "C") of zero.
A length of zero for the interval in the B bit vector
("C") means that the indicated stretch of bits in
the target bit vector (starting at position "C") is to
be replaced by B, i.e., is to be B.
A length of zero for the interval in the B bit vector
("C == 0") means that B is replaced, and that the
stretch of bits from the source bit vector is simply B
into the target bit vector at the indicated position ("C").
If both length parameters are zero, nothing is done at all.
Note that in contrast to any other method in this module (especially
"C", "C" and "C"), this method
B and B adapts the length of the resulting
bit vector as needed, as given by
$size = $vec2->Size(); # before
$size += $len1 - $len2; # after
(The only other method in this module that changes the size of a bit
vector is the method "C".)
In other words, replacing a given interval of bits in the target bit
vector with a longer or shorter stretch of bits from the source bit
vector, or simply inserting ("C") a stretch of bits into
or deleting ("C") an interval of bits from the target bit
vector will automatically increase or decrease, respectively, the size
of the target bit vector accordingly.
For the sake of generality, this may even result in a bit vector with
a size of zero (containing no bits at all).
This is also the reason why bit vectors of length zero are permitted
in this module in the first place, starting with version 5.0.
Finally, note that "C" and "C" may be identical, i.e.,
in-place processing is possible.
(If you think about that for a while or if you look at the code,
you will see that this is far from trivial!)
=item *
Cis_empty())>
Tests whether the given bit vector is empty, i.e., whether B of
its bits are cleared (in the "off" state).
In "big integer" arithmetic, this is equivalent to testing whether
the number stored in the bit vector is zero ("C<0>").
Returns "true" ("C<1>") if the bit vector is empty and "false" ("C<0>")
otherwise.
Note that this method also returns "true" ("C<1>") if the given bit
vector has a length of zero, i.e., if it contains no bits at all.
=item *
C